Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions config/rector/sets/cakephp60.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
declare(strict_types=1);

use Cake\Upgrade\Rector\Cake6\EventManagerOnRector;
use Cake\Upgrade\Rector\Cake6\RemoveAssignmentFromVoidMethodRector;
use Cake\Upgrade\Rector\Cake6\ReplaceCommandArgsIoWithPropertiesRector;
use Cake\Upgrade\Rector\Cake6\RouteBuilderToCallbackFirstRector;
use Cake\Upgrade\Rector\Cake6\VoidMethod;
use PHPStan\Type\ObjectType;
use Rector\Config\RectorConfig;
use Rector\Renaming\Rector\MethodCall\RenameMethodRector;
Expand Down Expand Up @@ -948,4 +950,37 @@
}
}
}

// Rename validChoice() to validateChoice() for console input classes
// @see https://github.com/cakephp/cakephp/pull/19220
$rectorConfig->ruleWithConfiguration(RenameMethodRector::class, [
new MethodCallRename('Cake\Console\ConsoleInputArgument', 'validChoice', 'validateChoice'),
new MethodCallRename('Cake\Console\ConsoleInputOption', 'validChoice', 'validateChoice'),
]);

// Remove assignments from methods that now return void instead of bool
// @see https://github.com/cakephp/cakephp/pull/19220
// @see https://github.com/cakephp/cakephp/pull/19243
$rectorConfig->ruleWithConfiguration(RemoveAssignmentFromVoidMethodRector::class, [
// ServerRequest::allowMethod() - returns void or throws MethodNotAllowedException
new VoidMethod('Cake\Http\ServerRequest', 'allowMethod'),
// Configure::load() - returns void or throws CakeException
new VoidMethod('Cake\Core\Configure', 'load'),
// ResponseEmitter::emit() - returns void
new VoidMethod('Cake\Http\ResponseEmitter', 'emit'),
// Session::close() - returns void or throws RuntimeException
new VoidMethod('Cake\Http\Session', 'close'),
// Table::deleteOrFail() - returns void or throws PersistenceFailedException
new VoidMethod('Cake\ORM\Table', 'deleteOrFail'),
// FixtureInterface::insert() - returns void
new VoidMethod('Cake\Datasource\FixtureInterface', 'insert'),
new VoidMethod('Cake\TestSuite\Fixture\TestFixture', 'insert'),
// FixtureInterface::truncate() - returns void
new VoidMethod('Cake\Datasource\FixtureInterface', 'truncate'),
new VoidMethod('Cake\TestSuite\Fixture\TestFixture', 'truncate'),
// ConsoleInputArgument::validateChoice() - returns void or throws ConsoleException
new VoidMethod('Cake\Console\ConsoleInputArgument', 'validateChoice'),
// ConsoleInputOption::validateChoice() - returns void or throws ConsoleException
new VoidMethod('Cake\Console\ConsoleInputOption', 'validateChoice'),
]);
};
113 changes: 113 additions & 0 deletions src/Rector/Cake6/RemoveAssignmentFromVoidMethodRector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<?php
declare(strict_types=1);

namespace Cake\Upgrade\Rector\Cake6;

use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Stmt\Expression;
use Rector\Contract\Rector\ConfigurableRectorInterface;
use Rector\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

/**
* Removes variable assignments from method calls that now return void.
*
* @see https://github.com/cakephp/cakephp/pull/19220
* @see https://github.com/cakephp/cakephp/pull/19243
*/
final class RemoveAssignmentFromVoidMethodRector extends AbstractRector implements ConfigurableRectorInterface
{
/**
* @var array<\Cake\Upgrade\Rector\Cake6\VoidMethod>
*/
private array $voidMethods = [];

public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
'Remove variable assignment from void method calls',
[
new ConfiguredCodeSample(
<<<'CODE_SAMPLE'
$result = $request->allowMethod(['POST']);
$result = Configure::load('app');
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
$request->allowMethod(['POST']);
Configure::load('app');
CODE_SAMPLE
,
[
new VoidMethod('Cake\Http\ServerRequest', 'allowMethod'),
new VoidMethod('Cake\Core\Configure', 'load'),
],
),
],
);
}

/**
* @return array<class-string<\PhpParser\Node>>
*/
public function getNodeTypes(): array
{
return [Expression::class];
}

/**
* @param \PhpParser\Node\Stmt\Expression $node
*/
public function refactor(Node $node): ?Node
{
if (!$node->expr instanceof Assign) {
return null;
}

$assign = $node->expr;

// Handle instance method calls
if ($assign->expr instanceof MethodCall) {
$methodCall = $assign->expr;
foreach ($this->voidMethods as $voidMethod) {
if (!$this->isObjectType($methodCall->var, $voidMethod->getObjectType())) {
continue;
}
if (!$this->isName($methodCall->name, $voidMethod->getMethod())) {
continue;
}

return new Expression($methodCall);
}
}

// Handle static method calls
if ($assign->expr instanceof StaticCall) {
$staticCall = $assign->expr;
foreach ($this->voidMethods as $voidMethod) {
if (!$this->isName($staticCall->class, $voidMethod->getClass())) {
continue;
}
if (!$this->isName($staticCall->name, $voidMethod->getMethod())) {
continue;
}

return new Expression($staticCall);
}
}

return null;
}

/**
* @param list<mixed> $configuration
*/
public function configure(array $configuration): void
{
$this->voidMethods = $configuration;
}
}
30 changes: 30 additions & 0 deletions src/Rector/Cake6/VoidMethod.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);

namespace Cake\Upgrade\Rector\Cake6;

use PHPStan\Type\ObjectType;

final class VoidMethod
{
public function __construct(
private readonly string $class,
private readonly string $method,
) {
}

public function getObjectType(): ObjectType
{
return new ObjectType($this->class);
}

public function getClass(): string
{
return $this->class;
}

public function getMethod(): string
{
return $this->method;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);

namespace App;

use Cake\Core\Configure;
use Cake\Http\ServerRequest;

class VoidMethods
{
public function test(ServerRequest $request): void
{
// Instance method - assignment should be removed
$result = $request->allowMethod(['POST']);

// Static method - assignment should be removed
$result = Configure::load('app');

// Without assignment - should stay as is
$request->allowMethod(['GET', 'POST']);
Configure::load('other');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);

namespace App;

use Cake\Core\Configure;
use Cake\Http\ServerRequest;

class VoidMethods
{
public function test(ServerRequest $request): void
{
$request->allowMethod(['POST']);

Configure::load('app');

// Without assignment - should stay as is
$request->allowMethod(['GET', 'POST']);
Configure::load('other');
}
}
Loading