Skip to content

Commit 4ab5d33

Browse files
dereuromarkclaudeLordSimal
authored
Add rector rule to rename Form::_execute() to process() (#353)
Form::_execute() is deprecated in CakePHP 5.x and should be renamed to process() which accepts the same parameters and has the same return type. This rector rule automatically handles the renaming while checking that process() doesn't already exist to avoid conflicts. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Kevin Pfeifer <kevin.pfeifer@sunlime.at>
1 parent 806c421 commit 4ab5d33

File tree

6 files changed

+202
-0
lines changed

6 files changed

+202
-0
lines changed

config/rector/sets/cakephp53.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?php
22
declare(strict_types=1);
33

4+
use Cake\Upgrade\Rector\Rector\ClassMethod\FormExecuteToProcessRector;
45
use Cake\Upgrade\Rector\Rector\MethodCall\EntityIsEmptyRector;
56
use Cake\Upgrade\Rector\Rector\MethodCall\EntityPatchRector;
67
use Cake\Upgrade\Rector\Rector\MethodCall\NewExprToFuncRector;
@@ -25,5 +26,6 @@
2526
]);
2627
$rectorConfig->rule(EntityIsEmptyRector::class);
2728
$rectorConfig->rule(EntityPatchRector::class);
29+
$rectorConfig->rule(FormExecuteToProcessRector::class);
2830
$rectorConfig->rule(QueryParamAccessRector::class);
2931
};
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Cake\Upgrade\Rector\Rector\ClassMethod;
5+
6+
use PhpParser\Node;
7+
use PhpParser\Node\Identifier;
8+
use PhpParser\Node\Stmt\Class_;
9+
use PhpParser\Node\Stmt\ClassMethod;
10+
use PHPStan\Type\ObjectType;
11+
use Rector\Rector\AbstractRector;
12+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
13+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
14+
15+
/**
16+
* Renames Form _execute() to process() if process() doesn't exist.
17+
*
18+
* Form::_execute() is deprecated in CakePHP 5.x. The method should be renamed to process()
19+
* which accepts the same parameters and has the same return type.
20+
*/
21+
final class FormExecuteToProcessRector extends AbstractRector
22+
{
23+
public function getRuleDefinition(): RuleDefinition
24+
{
25+
return new RuleDefinition(
26+
'Rename Form _execute() to process() if process() doesn\'t exist',
27+
[
28+
new CodeSample(
29+
<<<'CODE_SAMPLE'
30+
use Cake\Form\Form;
31+
32+
class ContactForm extends Form
33+
{
34+
protected function _execute(array $data, $form): bool
35+
{
36+
// Send email or save data
37+
return true;
38+
}
39+
}
40+
CODE_SAMPLE
41+
,
42+
<<<'CODE_SAMPLE'
43+
use Cake\Form\Form;
44+
45+
class ContactForm extends Form
46+
{
47+
protected function process(array $data, $form): bool
48+
{
49+
// Send email or save data
50+
return true;
51+
}
52+
}
53+
CODE_SAMPLE,
54+
),
55+
],
56+
);
57+
}
58+
59+
/**
60+
* @return array<class-string<\PhpParser\Node>>
61+
*/
62+
public function getNodeTypes(): array
63+
{
64+
return [Class_::class];
65+
}
66+
67+
/**
68+
* @param \PhpParser\Node\Stmt\Class_ $node
69+
*/
70+
public function refactor(Node $node): ?Node
71+
{
72+
if (!$this->isObjectType($node, new ObjectType('Cake\Form\Form'))) {
73+
return null;
74+
}
75+
76+
// Check if process() already exists
77+
$hasProcess = false;
78+
foreach ($node->stmts as $stmt) {
79+
if ($stmt instanceof ClassMethod && $this->isName($stmt->name, 'process')) {
80+
$hasProcess = true;
81+
break;
82+
}
83+
}
84+
85+
// If process() exists, don't rename _execute()
86+
if ($hasProcess) {
87+
return null;
88+
}
89+
90+
// Find and rename _execute() method
91+
$hasChanges = false;
92+
foreach ($node->stmts as $stmt) {
93+
if (!$stmt instanceof ClassMethod) {
94+
continue;
95+
}
96+
97+
if (!$this->isName($stmt->name, '_execute')) {
98+
continue;
99+
}
100+
101+
// Rename the method to process()
102+
$stmt->name = new Identifier('process');
103+
104+
$hasChanges = true;
105+
break;
106+
}
107+
108+
return $hasChanges ? $node : null;
109+
}
110+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace Cake\Upgrade\Test\TestCase\Rector\ClassMethod\FormExecuteToProcessRector\Fixture;
4+
5+
use Cake\Form\Form;
6+
7+
class ContactForm extends Form
8+
{
9+
protected function _execute(array $data, $form): bool
10+
{
11+
// Send email or save data
12+
return true;
13+
}
14+
}
15+
16+
?>
17+
-----
18+
<?php
19+
20+
namespace Cake\Upgrade\Test\TestCase\Rector\ClassMethod\FormExecuteToProcessRector\Fixture;
21+
22+
use Cake\Form\Form;
23+
24+
class ContactForm extends Form
25+
{
26+
protected function process(array $data, $form): bool
27+
{
28+
// Send email or save data
29+
return true;
30+
}
31+
}
32+
33+
?>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace Cake\Upgrade\Test\TestCase\Rector\ClassMethod\FormExecuteToProcessRector\Fixture;
4+
5+
use Cake\Form\Form;
6+
7+
class ContactForm extends Form
8+
{
9+
protected function _execute(array $data, $form): bool
10+
{
11+
// Old method
12+
return true;
13+
}
14+
15+
protected function process(array $data, $form): bool
16+
{
17+
// New method already exists
18+
return true;
19+
}
20+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Cake\Upgrade\Test\TestCase\Rector\ClassMethod\FormExecuteToProcessRector;
5+
6+
use Iterator;
7+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
8+
9+
final class FormExecuteToProcessRectorTest extends AbstractRectorTestCase
10+
{
11+
/**
12+
* @dataProvider provideData()
13+
*/
14+
public function test(string $filePath): void
15+
{
16+
$this->doTestFile($filePath);
17+
}
18+
19+
public static function provideData(): Iterator
20+
{
21+
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
22+
}
23+
24+
public function provideConfigFilePath(): string
25+
{
26+
return __DIR__ . '/config/configured_rule.php';
27+
}
28+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
use Cake\Upgrade\Rector\Rector\ClassMethod\FormExecuteToProcessRector;
5+
use Rector\Config\RectorConfig;
6+
7+
return static function (RectorConfig $rectorConfig): void {
8+
$rectorConfig->rule(FormExecuteToProcessRector::class);
9+
};

0 commit comments

Comments
 (0)