Skip to content

Commit

Permalink
Adds the ReverseCondiationableMethodCallRector (#245)
Browse files Browse the repository at this point in the history
* Adds the ReverseCondiationableMethodCallRector

* fix docs
  • Loading branch information
peterfox authored Aug 30, 2024
1 parent d237f6e commit 037f997
Show file tree
Hide file tree
Showing 9 changed files with 217 additions and 1 deletion.
2 changes: 2 additions & 0 deletions config/sets/laravel-code-quality.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

use Rector\Config\RectorConfig;
use RectorLaravel\Rector\Assign\CallOnAppArrayAccessToStandaloneAssignRector;
use RectorLaravel\Rector\MethodCall\ReverseConditionableMethodCallRector;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->import(__DIR__ . '/../config.php');
$rectorConfig->rule(CallOnAppArrayAccessToStandaloneAssignRector::class);
$rectorConfig->rule(ReverseConditionableMethodCallRector::class);
};
22 changes: 21 additions & 1 deletion docs/rector_rules_overview.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 65 Rules Overview
# 66 Rules Overview

## AbortIfRector

Expand Down Expand Up @@ -1231,6 +1231,26 @@ Change static `validate()` method to `$request->validate()`

<br>

## ReverseConditionableMethodCallRector

Reverse conditionable method calls

- class: [`RectorLaravel\Rector\MethodCall\ReverseConditionableMethodCallRector`](../src/Rector/MethodCall/ReverseConditionableMethodCallRector.php)

```diff
-$conditionable->when(!$condition, function () {});
+$conditionable->unless($condition, function () {});
```

<br>

```diff
-$conditionable->unless(!$condition, function () {});
+$conditionable->when($condition, function () {});
```

<br>

## RouteActionCallableRector

Use PHP callable syntax instead of string syntax for controller route declarations.
Expand Down
88 changes: 88 additions & 0 deletions src/Rector/MethodCall/ReverseConditionableMethodCallRector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

namespace RectorLaravel\Rector\MethodCall;

use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\BooleanNot;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Identifier;
use PHPStan\Type\ObjectType;
use Rector\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

/**
* @see \RectorLaravel\Tests\Rector\MethodCall\ReverseConditionableMethodCallRector\ReverseConditionableMethodCallRectorTest
*/
class ReverseConditionableMethodCallRector extends AbstractRector
{
private const CONDITIONABLE_TRAIT = 'Illuminate\Support\Traits\Conditionable';

public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
'Reverse conditionable method calls',
[
new CodeSample(<<<'CODE_SAMPLE'
$conditionable->when(!$condition, function () {});
CODE_SAMPLE,
<<<'CODE_SAMPLE'
$conditionable->unless($condition, function () {});
CODE_SAMPLE
),
new CodeSample(<<<'CODE_SAMPLE'
$conditionable->unless(!$condition, function () {});
CODE_SAMPLE,
<<<'CODE_SAMPLE'
$conditionable->when($condition, function () {});
CODE_SAMPLE
),
]
);
}

public function getNodeTypes(): array
{
return [MethodCall::class];
}

/**
* @param MethodCall $node
*/
public function refactor(Node $node): ?MethodCall
{
if (! $this->isObjectType($node->var, new ObjectType(self::CONDITIONABLE_TRAIT))) {
return null;
}

if (! $this->isNames($node->name, ['when', 'unless'])) {
return null;
}

if ($node->isFirstClassCallable()) {
return null;
}

if ($node->getArgs() === []) {
return null;
}

$arg = $node->getArgs()[0];

if (! $node->name instanceof Identifier) {
return null;
}

if ($arg->value instanceof BooleanNot) {
$node->args[0] = new Arg($arg->value->expr);
$name = $node->name->toString() === 'when' ? 'unless' : 'when';

$node->name = new Identifier($name);

return $node;
}

return null;
}
}
18 changes: 18 additions & 0 deletions stubs/Illuminate/Support/Traits/Conditionable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Illuminate\Support\Traits;

if (trait_exists('Illuminate\Support\Traits\Conditionable')) {
return;
}

trait Conditionable
{
public function when($value = null, ?callable $callback = null, ?callable $default = null)
{
}

public function unless($value = null, ?callable $callback = null, ?callable $default = null)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace RectorLaravel\Tests\Rector\MethodCall\ReverseConditionableMethodCallRector\Fixture;

use RectorLaravel\Tests\Rector\MethodCall\ReverseConditionableMethodCallRector\Source\ConditionableExample;

$conditionable = new ConditionableExample();

$conditionable->when(!true, function () {});
$conditionable->unless(!false, function () {});

?>
-----
<?php

namespace RectorLaravel\Tests\Rector\MethodCall\ReverseConditionableMethodCallRector\Fixture;

use RectorLaravel\Tests\Rector\MethodCall\ReverseConditionableMethodCallRector\Source\ConditionableExample;

$conditionable = new ConditionableExample();

$conditionable->unless(true, function () {});
$conditionable->when(false, function () {});

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace RectorLaravel\Tests\Rector\MethodCall\ReverseConditionableMethodCallRector\Fixture;

$conditionable = new \stdClass();

$conditionable->when(!true, function () {});
$conditionable->unless(!false, function () {});

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace RectorLaravel\Tests\Rector\MethodCall\ReverseConditionableMethodCallRector;

use Iterator;
use PHPUnit\Framework\Attributes\DataProvider;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

final class ReverseConditionableMethodCallRectorTest extends AbstractRectorTestCase
{
public static function provideData(): Iterator
{
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
}

/**
* @test
*/
#[DataProvider('provideData')]
public function test(string $filePath): void
{
$this->doTestFile($filePath);
}

public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace RectorLaravel\Tests\Rector\MethodCall\ReverseConditionableMethodCallRector\Source;

use Illuminate\Support\Traits\Conditionable;

class ConditionableExample
{
use Conditionable;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use RectorLaravel\Rector\MethodCall\ReverseConditionableMethodCallRector;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->import(__DIR__ . '/../../../../../config/config.php');

$rectorConfig->rule(ReverseConditionableMethodCallRector::class);
};

0 comments on commit 037f997

Please sign in to comment.