Skip to content

Commit

Permalink
[Laravel110] Adds ModelCastsPropertyToCastsMethodRector rule (#173)
Browse files Browse the repository at this point in the history
* Adds ModelCastsPropertyToCastsMethodRector rule

* Set method to protected instead of public
  • Loading branch information
peterfox authored Jan 27, 2024
1 parent 30f1bfd commit 6a9ad4a
Show file tree
Hide file tree
Showing 12 changed files with 254 additions and 3 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use Rector\Config\RectorConfig;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->sets([
LaravelSetList::LARAVEL_100
LaravelSetList::LARAVEL_110
]);
};
```
Expand Down
14 changes: 14 additions & 0 deletions config/sets/laravel110.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use RectorLaravel\Rector\Class_\ModelCastsPropertyToCastsMethodRector;

// see https://laravel.com/docs/11.x/upgrade
return static function (RectorConfig $rectorConfig): void {
$rectorConfig->import(__DIR__ . '/../config.php');

// https://github.com/laravel/framework/pull/47237
$rectorConfig->rule(ModelCastsPropertyToCastsMethodRector::class);
};
11 changes: 11 additions & 0 deletions config/sets/level/up-to-laravel-110.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use RectorLaravel\Set\LaravelLevelSetList;
use RectorLaravel\Set\LaravelSetList;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->sets([LaravelSetList::LARAVEL_110, LaravelLevelSetList::UP_TO_LARAVEL_100]);
};
12 changes: 10 additions & 2 deletions docs/rector_rules_overview.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 50 Rules Overview
# 51 Rules Overview

## AddArgumentDefaultValueRector

Expand Down Expand Up @@ -698,6 +698,14 @@ Change minutes argument to seconds in `Illuminate\Contracts\Cache\Store` and Ill

<br>

## ModelCastsPropertyToCastsMethodRector

Refactor Model `$casts` property with `casts()` method

- class: [`RectorLaravel\Rector\Class_\ModelCastsPropertyToCastsMethodRector`](../src/Rector/Class_/ModelCastsPropertyToCastsMethodRector.php)

<br>

## NotFilledBlankFuncCallToBlankFilledFuncCallRector

Swap the use of NotBooleans used with `filled()` and `blank()` to the correct helper.
Expand Down Expand Up @@ -1095,4 +1103,4 @@ Use `$this->components` property within commands
}
```

<br>
<br>
96 changes: 96 additions & 0 deletions src/Rector/Class_/ModelCastsPropertyToCastsMethodRector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php

namespace RectorLaravel\Rector\Class_;

use PhpParser\BuilderFactory;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\Stmt\Return_;
use PHPStan\Type\ObjectType;
use Rector\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

/**
* @see \RectorLaravel\Tests\Rector\Class_\ModelCastsPropertyToCastsMethodRector\ModelCastsPropertyToCastsMethodRectorTest
*/
class ModelCastsPropertyToCastsMethodRector extends AbstractRector
{
public function __construct(protected BuilderFactory $builderFactory)
{
}

public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Refactor Model $casts property with casts() method', [
new CodeSample(
<<<'CODE_SAMPLE'
use Illuminate\Database\Eloquent\Model;
class Person extends Model
{
protected $casts = [
'age' => 'integer',
];
}
CODE_SAMPLE,
<<<'CODE_SAMPLE'
use Illuminate\Database\Eloquent\Model;
class Person extends Model
{
protected function casts(): array
{
return [
'age' => 'integer',
];
}
}
CODE_SAMPLE,
),
]);
}

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

/**
* @param Class_ $node
*/
public function refactor(Node $node): ?Class_
{
// Check if it is a Model
if (! $this->isObjectType($node, new ObjectType('Illuminate\Database\Eloquent\Model'))) {

return null;
}

// Check if there is already a casts() method
foreach ($node->stmts as $stmt) {
if ($stmt instanceof ClassMethod && $this->isName($stmt, 'casts')) {
return null;
}
}

// Check if there is a protected $casts property
foreach ($node->stmts as $index => $stmt) {
if ($stmt instanceof Property && ($this->isName($stmt, 'casts') && $stmt->isProtected())) {
$method = $this->builderFactory->method('casts')
->setReturnType('array')
->makeProtected();
// convert the property to a return statement
$method->addStmt(new Return_($stmt->props[0]->default));
unset($node->stmts[$index]);
$node->stmts[] = $method->getNode();

return $node;
}
}

return null;
}
}
5 changes: 5 additions & 0 deletions src/Set/LaravelLevelSetList.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,9 @@ final class LaravelLevelSetList implements SetListInterface
* @var string
*/
final public const UP_TO_LARAVEL_100 = __DIR__ . '/../../config/sets/level/up-to-laravel-100.php';

/**
* @var string
*/
final public const UP_TO_LARAVEL_110 = __DIR__ . '/../../config/sets/level/up-to-laravel-110.php';
}
5 changes: 5 additions & 0 deletions src/Set/LaravelSetList.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ final class LaravelSetList implements SetListInterface
*/
final public const LARAVEL_100 = __DIR__ . '/../../config/sets/laravel100.php';

/**
* @var string
*/
final public const LARAVEL_110 = __DIR__ . '/../../config/sets/laravel110.php';

/**
* @var string
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace RectorLaravel\Tests\Rector\Class_\ModelCastsPropertyToCastsMethodRector\Fixture;

use Illuminate\Database\Eloquent\Model;

class CastsPropertyExists extends Model
{
protected $casts = [
'birthday' => 'datetime',
'age' => 'integer',
];
}

?>
-----
<?php

namespace RectorLaravel\Tests\Rector\Class_\ModelCastsPropertyToCastsMethodRector\Fixture;

use Illuminate\Database\Eloquent\Model;

class CastsPropertyExists extends Model
{
protected function casts(): array
{
return [
'birthday' => 'datetime',
'age' => 'integer',
];
}
}

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

namespace RectorLaravel\Tests\Rector\Class_\ModelCastsPropertyToCastsMethodRector\Fixture;

use Illuminate\Database\Eloquent\Model;

class ClassWithCastsMethod extends Model
{
protected $casts = [
'name' => 'string',
];

private function casts(): array
{
return [
'birthday' => 'datetime',
'age' => 'integer',
];
}
}

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

namespace RectorLaravel\Tests\Rector\Class_\ModelCastsPropertyToCastsMethodRector\Fixture;

class NonModelClass
{
protected $casts = [
'birthday' => 'datetime',
'age' => 'integer',
];
}

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

declare(strict_types=1);

namespace RectorLaravel\Tests\Rector\Class_\ModelCastsPropertyToCastsMethodRector;

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

final class ModelCastsPropertyToCastsMethodRectorTest 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,12 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use RectorLaravel\Rector\Class_\ModelCastsPropertyToCastsMethodRector;

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

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

0 comments on commit 6a9ad4a

Please sign in to comment.