rector/rules/laravel/src/Rector/ClassMethod/AddParentBootToModelClassMethodRector.php
Tomas Votruba 4c6da2c4bf
[Laravel 5.7] Add parent boot rule (#4580)
* move file to templates, to remove confusion in the root

* use stable symplify

* [Laravel] Add AddParentBootToModelClassMethodRector

* [ci-review] Generate Rector & Nodes documentation

* [ci-review] propagate monorepo dependencies

* [ci-review] Rector Rectify

Co-authored-by: rector-bot <tomas@getrector.org>
2020-11-11 17:09:57 +00:00

121 lines
3.0 KiB
PHP

<?php
declare(strict_types=1);
namespace Rector\Laravel\Rector\ClassMethod;
use PhpParser\Node;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\Nette\NodeAnalyzer\StaticCallAnalyzer;
/**
* @see https://laracasts.com/discuss/channels/laravel/laravel-57-upgrade-observer-problem
*
* @see \Rector\Laravel\Tests\Rector\ClassMethod\AddParentBootToModelClassMethodRector\AddParentBootToModelClassMethodRectorTest
*/
final class AddParentBootToModelClassMethodRector extends AbstractRector
{
/**
* @var string
*/
private const BOOT = 'boot';
/**
* @var StaticCallAnalyzer
*/
private $staticCallAnalyzer;
public function __construct(StaticCallAnalyzer $staticCallAnalyzer)
{
$this->staticCallAnalyzer = $staticCallAnalyzer;
}
public function getDefinition(): RectorDefinition
{
return new RectorDefinition(
'Add parent::boot(); call to boot() class method in child of Illuminate\Database\Eloquent\Model',
[
new CodeSample(
<<<'CODE_SAMPLE'
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
public function boot()
{
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
public function boot()
{
parent::boot();
}
}
CODE_SAMPLE
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [ClassMethod::class];
}
/**
* @param ClassMethod $node
*/
public function refactor(Node $node): ?Node
{
if (! $this->isInObjectType($node, 'Illuminate\Database\Eloquent\Model')) {
return null;
}
if (! $this->isName($node->name, self::BOOT)) {
return null;
}
foreach ((array) $node->stmts as $key => $classMethodStmt) {
if ($classMethodStmt instanceof Expression) {
$classMethodStmt = $classMethodStmt->expr;
}
// is in the 1st position? → only correct place
// @see https://laracasts.com/discuss/channels/laravel/laravel-57-upgrade-observer-problem?page=0#reply=454409
if (! $this->staticCallAnalyzer->isParentCallNamed($classMethodStmt, self::BOOT)) {
continue;
}
if ($key === 0) {
return null;
}
// wrong location → remove it
unset($node->stmts[$key]);
}
// missing, we need to add one
$staticCall = $this->nodeFactory->createStaticCall('parent', self::BOOT);
$parentStaticCallExpression = new Expression($staticCall);
$node->stmts = array_merge([$parentStaticCallExpression], (array) $node->stmts);
return $node;
}
}