Skip to content

Commit

Permalink
[Laravel] Add AddParentBootToModelClassMethodRector
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed Nov 11, 2020
1 parent e53cdae commit 459d114
Show file tree
Hide file tree
Showing 10 changed files with 251 additions and 113 deletions.
46 changes: 40 additions & 6 deletions config/set/laravel57.php
Original file line number Diff line number Diff line change
@@ -1,21 +1,55 @@
<?php

declare(strict_types=1);

use Rector\Generic\Rector\ClassMethod\ArgumentAdderRector;
use Rector\Generic\Rector\ClassMethod\ArgumentRemoverRector;
use Rector\Generic\Rector\ClassMethod\ChangeMethodVisibilityRector;
use Rector\Generic\ValueObject\ArgumentAdder;
use Rector\Generic\ValueObject\ArgumentRemover;
use Rector\Generic\ValueObject\ChangeMethodVisibility;
use Rector\Laravel\Rector\ClassMethod\AddParentBootToModelClassMethodRector;
use Rector\Laravel\Rector\StaticCall\Redirect301ToPermanentRedirectRector;
use function Rector\SymfonyPhpConfig\inline_value_objects;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

# see: https://laravel.com/docs/5.7/upgrade
return static function (\Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator $containerConfigurator) : void {
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(\Rector\Generic\Rector\ClassMethod\ChangeMethodVisibilityRector::class)->call('configure', [[\Rector\Generic\Rector\ClassMethod\ChangeMethodVisibilityRector::METHOD_VISIBILITIES => \Rector\SymfonyPhpConfig\inline_value_objects([new \Rector\Generic\ValueObject\ChangeMethodVisibility('Illuminate\Routing\Router', 'addRoute', 'public'), new \Rector\Generic\ValueObject\ChangeMethodVisibility('Illuminate\Contracts\Auth\Access\Gate', 'raw', 'public')])]]);
$services->set(\Rector\Generic\Rector\ClassMethod\ArgumentAdderRector::class)->call('configure', [[\Rector\Generic\Rector\ClassMethod\ArgumentAdderRector::ADDED_ARGUMENTS => \Rector\SymfonyPhpConfig\inline_value_objects([new \Rector\Generic\ValueObject\ArgumentAdder('Illuminate\Auth\Middleware\Authenticate', 'authenticate', 0, 'request'), new \Rector\Generic\ValueObject\ArgumentAdder('Illuminate\Foundation\Auth\ResetsPasswords', 'sendResetResponse', 0, 'request', \null, 'Illuminate\Http\Illuminate\Http'), new \Rector\Generic\ValueObject\ArgumentAdder('Illuminate\Foundation\Auth\SendsPasswordResetEmails', 'sendResetLinkResponse', 0, 'request', \null, 'Illuminate\Http\Illuminate\Http')])]]);
$services->set(\Rector\Laravel\Rector\StaticCall\Redirect301ToPermanentRedirectRector::class);
$services->set(\Rector\Generic\Rector\ClassMethod\ArgumentRemoverRector::class)->call('configure', [[\Rector\Generic\Rector\ClassMethod\ArgumentRemoverRector::REMOVED_ARGUMENTS => \Rector\SymfonyPhpConfig\inline_value_objects([new \Rector\Generic\ValueObject\ArgumentRemover('Illuminate\Foundation\Application', 'register', 1, ['name' => 'options'])])]]);
$services->set(\Rector\Laravel\Rector\Class_\AddParentBootToModelClassMethodRector::class);
$services->set(ChangeMethodVisibilityRector::class)->call('configure', [[
ChangeMethodVisibilityRector::METHOD_VISIBILITIES => inline_value_objects([
new ChangeMethodVisibility('Illuminate\Routing\Router', 'addRoute', 'public'),
new ChangeMethodVisibility('Illuminate\Contracts\Auth\Access\Gate', 'raw', 'public'),
]),
]]);
$services->set(ArgumentAdderRector::class)->call('configure', [[
ArgumentAdderRector::ADDED_ARGUMENTS => inline_value_objects([
new ArgumentAdder('Illuminate\Auth\Middleware\Authenticate', 'authenticate', 0, 'request'),
new ArgumentAdder(
'Illuminate\Foundation\Auth\ResetsPasswords',
'sendResetResponse',
0,
'request',
null,
'Illuminate\Http\Illuminate\Http'
),
new ArgumentAdder(
'Illuminate\Foundation\Auth\SendsPasswordResetEmails',
'sendResetLinkResponse',
0,
'request',
null,
'Illuminate\Http\Illuminate\Http'
),
]),
]]);
$services->set(Redirect301ToPermanentRedirectRector::class);
$services->set(ArgumentRemoverRector::class)->call('configure', [[
ArgumentRemoverRector::REMOVED_ARGUMENTS => inline_value_objects([
new ArgumentRemover('Illuminate\Foundation\Application', 'register', 1, [
'name' => 'options',
]),
]),
]]);
$services->set(AddParentBootToModelClassMethodRector::class);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<?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 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, '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, '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', 'boot');
$parentStaticCallExpression = new Expression($staticCall);

$node->stmts = array_merge([$parentStaticCallExpression], (array) $node->stmts);

return $node;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,30 @@

declare(strict_types=1);

namespace Rector\Laravel\Tests\Rector\Class_\AddParentBootToModelClassMethodRector;
namespace Rector\Laravel\Tests\Rector\ClassMethod\AddParentBootToModelClassMethodRector;

use Iterator;
use Rector\Laravel\Rector\ClassMethod\AddParentBootToModelClassMethodRector;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;

final class AddParentBootToModelClassMethodRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(\Symplify\SmartFileSystem\SmartFileInfo $fileInfo): void
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}

public function provideData(): \Iterator
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}

protected function getRectorClass(): string
{
return \Rector\Laravel\Rector\Class_\AddParentBootToModelClassMethodRector::class;
return AddParentBootToModelClassMethodRector::class;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace Rector\Laravel\Tests\Rector\ClassMethod\AddParentBootToModelClassMethodRector\Fixture;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
public function boot()
{
}
}

?>
-----
<?php

namespace Rector\Laravel\Tests\Rector\ClassMethod\AddParentBootToModelClassMethodRector\Fixture;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
public function boot()
{
parent::boot();
}
}

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

namespace Rector\Laravel\Tests\Rector\ClassMethod\AddParentBootToModelClassMethodRector\Fixture;

use Illuminate\Database\Eloquent\Model;

class OnTheLastLine extends Model
{
public function boot()
{
$value = 1000;
parent::boot();
}
}

?>
-----
<?php

namespace Rector\Laravel\Tests\Rector\ClassMethod\AddParentBootToModelClassMethodRector\Fixture;

use Illuminate\Database\Eloquent\Model;

class OnTheLastLine extends Model
{
public function boot()
{
parent::boot();
$value = 1000;
}
}

?>

This file was deleted.

Loading

0 comments on commit 459d114

Please sign in to comment.