Skip to content

Commit

Permalink
Allow configuring EloquentOrderByToLatestOrOldestRector (#148)
Browse files Browse the repository at this point in the history
* Allow configuring EloquentOrderByToLatestOrOldestRector
  • Loading branch information
johnbacon authored Dec 8, 2023
1 parent cf00851 commit a52689f
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 15 deletions.
35 changes: 33 additions & 2 deletions docs/rector_rules_overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -490,17 +490,48 @@ The EloquentMagicMethodToQueryBuilderRule is designed to automatically transform

Changes `orderBy()` to `latest()` or `oldest()`

:wrench: **configure it!**

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

```php
<?php

declare(strict_types=1);

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

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->ruleWithConfiguration(EloquentOrderByToLatestOrOldestRector::class, [
EloquentOrderByToLatestOrOldestRector::ALLOWED_PATTERNS => [
'submitted_a*',
'*tested_at',
'$allowed_variable_name',
],
]);
};
```


```diff
use Illuminate\Database\Eloquent\Builder;

$column = 'tested_at';

-$builder->orderBy('created_at');
-$builder->orderBy('created_at', 'desc');
-$builder->orderBy('deleted_at');
-$builder->orderBy('submitted_at');
-$builder->orderByDesc('submitted_at');
-$builder->orderBy($allowed_variable_name);
+$builder->oldest();
+$builder->latest();
+$builder->oldest('deleted_at');
+$builder->oldest('submitted_at');
+$builder->latest('submitted_at');
+$builder->oldest($allowed_variable_name);
$builder->orderBy($unallowed_variable_name);
$builder->orderBy('unallowed_column_name');
```

<br>
Expand Down
91 changes: 81 additions & 10 deletions src/Rector/MethodCall/EloquentOrderByToLatestOrOldestRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,63 @@
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PHPStan\Type\ObjectType;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
use Webmozart\Assert\Assert;

/**
* @see \RectorLaravel\Tests\Rector\MethodCall\EloquentOrderByToLatestOrOldestRector\EloquentOrderByToLatestOrOldestRectorTest
*/
class EloquentOrderByToLatestOrOldestRector extends AbstractRector
class EloquentOrderByToLatestOrOldestRector extends AbstractRector implements ConfigurableRectorInterface
{
/**
* @var string
*/
final public const ALLOWED_PATTERNS = 'allowed_patterns';

/**
* @var string[]
*/
private array $allowedPatterns = [];

public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
'Changes orderBy() to latest() or oldest()',
[
new CodeSample(
<<<'CODE_SAMPLE'
new ConfiguredCodeSample(<<<'CODE_SAMPLE'
use Illuminate\Database\Eloquent\Builder;
$column = 'tested_at';
$builder->orderBy('created_at');
$builder->orderBy('created_at', 'desc');
$builder->orderBy('deleted_at');
$builder->orderBy('submitted_at');
$builder->orderByDesc('submitted_at');
$builder->orderBy($allowed_variable_name);
$builder->orderBy($unallowed_variable_name);
$builder->orderBy('unallowed_column_name');
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
,<<<'CODE_SAMPLE'
use Illuminate\Database\Eloquent\Builder;
$column = 'tested_at';
$builder->oldest();
$builder->latest();
$builder->oldest('deleted_at');
$builder->oldest('submitted_at');
$builder->latest('submitted_at');
$builder->oldest($allowed_variable_name);
$builder->orderBy($unallowed_variable_name);
$builder->orderBy('unallowed_column_name');
CODE_SAMPLE
,
),
, [self::ALLOWED_PATTERNS => [
'submitted_a*',
'*tested_at',
'$allowed_variable_name',]]),
]
);
}
Expand All @@ -54,7 +79,7 @@ public function refactor(Node $node): ?Node
return null;
}

if ($this->isOrderByMethodCall($node)) {
if ($this->isOrderByMethodCall($node) && $this->isAllowedPattern($node)) {
return $this->convertOrderByToLatest($node);
}

Expand All @@ -71,6 +96,39 @@ private function isOrderByMethodCall(MethodCall $methodCall): bool
&& count($methodCall->args) > 0;
}

private function isAllowedPattern(MethodCall $methodCall): bool
{
$columnArg = $methodCall->args[0]->value ?? null;

// If no patterns are specified, consider all column names as matching
if ($this->allowedPatterns === []) {
return true;
}

if ($columnArg instanceof Node\Scalar\String_) {
$columnName = $columnArg->value;

// If specified, only allow certain patterns
foreach ($this->allowedPatterns as $pattern) {
if (fnmatch($pattern, $columnName)) {
return true;
}
}
}

if ($columnArg instanceof Node\Expr\Variable && is_string($columnArg->name)) {
// Check against allowed patterns
foreach ($this->allowedPatterns as $pattern) {
if (fnmatch(ltrim($pattern, '$'), $columnArg->name)) {
return true;
}
}
}


return false;
}

private function convertOrderByToLatest(MethodCall $methodCall): MethodCall
{
if (! isset($methodCall->args[0]) && ! $methodCall->args[0] instanceof Node\VariadicPlaceholder) {
Expand Down Expand Up @@ -107,4 +165,17 @@ private function convertOrderByToLatest(MethodCall $methodCall): MethodCall

return $methodCall;
}


/**
* @param mixed[] $configuration
*/
public function configure(array $configuration): void
{
$allowedPatterns = $configuration[self::ALLOWED_PATTERNS] ?? [];
Assert::isArray($allowedPatterns);
Assert::allString($allowedPatterns);

$this->allowedPatterns = $allowedPatterns;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ $query->orderBy('created_at');
$query->orderBy('created_at', 'desc');
$query->orderBy('submitted_at');
$query->orderByDesc('submitted_at');
$query->orderBy($column);
$query->orderBy($allowed_variable_name);

?>
-----
Expand All @@ -28,6 +28,6 @@ $query->oldest();
$query->latest();
$query->oldest('submitted_at');
$query->latest('submitted_at');
$query->oldest($column);
$query->oldest($allowed_variable_name);

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

namespace RectorLaravel\Tests\Rector\Cast\DatabaseExpressionCastsToMethodCall\Fixture;

$query->orderBy($unallowed_variable_name);
$query->orderBy('unallowed_column_name');

?>
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,15 @@
return static function (RectorConfig $rectorConfig): void {
$rectorConfig->import(__DIR__ . '/../../../../../config/config.php');

$rectorConfig->rule(EloquentOrderByToLatestOrOldestRector::class);
$rectorConfig->ruleWithConfiguration(
EloquentOrderByToLatestOrOldestRector::class,
[
EloquentOrderByToLatestOrOldestRector::ALLOWED_PATTERNS => [
'created_at',
'submitted_a*',
'*tested_at',
'$allowed_variable_name',
],
],
);
};

0 comments on commit a52689f

Please sign in to comment.