Skip to content

Commit efcfd0a

Browse files
CopilotADmad
authored andcommitted
Add rector rule for EventManager::on() signature change in CakePHP 6.0 (#356)
* Initial plan * Add EventManagerOnRector for EventManager::on() signature change Co-authored-by: ADmad <142658+ADmad@users.noreply.github.com> * Refine EventManagerOnRector and update test fixture Co-authored-by: ADmad <142658+ADmad@users.noreply.github.com> * Revert accidental composer.json changes Co-authored-by: ADmad <142658+ADmad@users.noreply.github.com> * Change type check to EventManagerInterface instead of EventManager Co-authored-by: ADmad <142658+ADmad@users.noreply.github.com> * Fix coding style: remove trailing whitespace Co-authored-by: ADmad <142658+ADmad@users.noreply.github.com> * Fix coding style: remove blank line after function opening brace Co-authored-by: ADmad <142658+ADmad@users.noreply.github.com> * Fix docblock format: add blank line before last @see tag Co-authored-by: ADmad <142658+ADmad@users.noreply.github.com> * Fix CS errors --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: ADmad <142658+ADmad@users.noreply.github.com> Co-authored-by: ADmad <admad.coder@gmail.com>
1 parent 069a0cf commit efcfd0a

File tree

5 files changed

+182
-0
lines changed

5 files changed

+182
-0
lines changed

config/rector/sets/cakephp60.php

Lines changed: 3 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\MethodCall\EventManagerOnRector;
45
use PHPStan\Type\ObjectType;
56
use Rector\Config\RectorConfig;
67
use Rector\Renaming\Rector\MethodCall\RenameMethodRector;
@@ -16,6 +17,8 @@
1617

1718
# @see https://book.cakephp.org/6/en/appendices/6-0-migration-guide.html
1819
return static function (RectorConfig $rectorConfig): void {
20+
// EventManager::on() signature change
21+
$rectorConfig->rule(EventManagerOnRector::class);
1922

2023
// Changes related to the accessible => patchable rename
2124
$rectorConfig->ruleWithConfiguration(RenameMethodRector::class, [
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Cake\Upgrade\Rector\Rector\MethodCall;
5+
6+
use PhpParser\Node;
7+
use PhpParser\Node\Expr\MethodCall;
8+
use PHPStan\Type\ObjectType;
9+
use Rector\Rector\AbstractRector;
10+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
11+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
12+
13+
/**
14+
* Swaps the 2nd and 3rd arguments of EventManagerInterface::on() when called with 3 arguments.
15+
*
16+
* @see \Cake\Upgrade\Test\TestCase\Rector\MethodCall\EventManagerOnRector\EventManagerOnRectorTest
17+
*/
18+
final class EventManagerOnRector extends AbstractRector
19+
{
20+
public function getRuleDefinition(): RuleDefinition
21+
{
22+
return new RuleDefinition(
23+
'Swaps the 2nd and 3rd arguments of EventManagerInterface::on() to match new signature',
24+
[
25+
new CodeSample(
26+
<<<'CODE_SAMPLE'
27+
$eventManager->on('Model.beforeSave', ['priority' => 90], $callable);
28+
CODE_SAMPLE
29+
,
30+
<<<'CODE_SAMPLE'
31+
$eventManager->on('Model.beforeSave', $callable, ['priority' => 90]);
32+
CODE_SAMPLE,
33+
),
34+
],
35+
);
36+
}
37+
38+
/**
39+
* @return array<class-string<\PhpParser\Node>>
40+
*/
41+
public function getNodeTypes(): array
42+
{
43+
return [MethodCall::class];
44+
}
45+
46+
/**
47+
* @param \PhpParser\Node\Expr\MethodCall $node
48+
*/
49+
public function refactor(Node $node): ?Node
50+
{
51+
// Check if this is a call to the 'on' method
52+
if (!$this->isName($node->name, 'on')) {
53+
return null;
54+
}
55+
56+
// Check if the object implements EventManagerInterface
57+
if (!$this->isObjectType($node->var, new ObjectType('Cake\Event\EventManagerInterface'))) {
58+
return null;
59+
}
60+
61+
// Only process if there are exactly 3 arguments
62+
if (count($node->args) !== 3) {
63+
return null;
64+
}
65+
66+
// Swap the 2nd and 3rd arguments
67+
$secondArg = $node->args[1];
68+
$thirdArg = $node->args[2];
69+
70+
$node->args[1] = $thirdArg;
71+
$node->args[2] = $secondArg;
72+
73+
return $node;
74+
}
75+
}
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\MethodCall\EventManagerOnRector;
5+
6+
use Iterator;
7+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
8+
9+
final class EventManagerOnRectorTest 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: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
namespace Cake\Upgrade\Test\TestCase\Rector\MethodCall\EventManagerOnRector\Fixture;
4+
5+
use Cake\Event\EventManager;
6+
7+
class Fixture
8+
{
9+
public function run()
10+
{
11+
$eventManager = EventManager::instance();
12+
13+
// Should be transformed - 3 arguments with array literal
14+
$eventManager->on('Model.beforeSave', ['priority' => 90], $callable);
15+
16+
// Should be transformed - 3 arguments with different options
17+
$eventManager->on('Controller.initialize', ['priority' => 10], function () {
18+
return true;
19+
});
20+
21+
// Should NOT be transformed - 2 arguments
22+
$eventManager->on('Model.afterSave', $callable);
23+
24+
// Should NOT be transformed - 1 argument
25+
$eventManager->on('Model.afterDelete');
26+
27+
// Should be transformed - 3 arguments with variable
28+
$options = ['priority' => 100];
29+
$eventManager->on('Model.beforeFind', $options, $handler);
30+
}
31+
}
32+
33+
?>
34+
-----
35+
<?php
36+
37+
namespace Cake\Upgrade\Test\TestCase\Rector\MethodCall\EventManagerOnRector\Fixture;
38+
39+
use Cake\Event\EventManager;
40+
41+
class Fixture
42+
{
43+
public function run()
44+
{
45+
$eventManager = EventManager::instance();
46+
47+
// Should be transformed - 3 arguments with array literal
48+
$eventManager->on('Model.beforeSave', $callable, ['priority' => 90]);
49+
50+
// Should be transformed - 3 arguments with different options
51+
$eventManager->on('Controller.initialize', function () {
52+
return true;
53+
}, ['priority' => 10]);
54+
55+
// Should NOT be transformed - 2 arguments
56+
$eventManager->on('Model.afterSave', $callable);
57+
58+
// Should NOT be transformed - 1 argument
59+
$eventManager->on('Model.afterDelete');
60+
61+
// Should be transformed - 3 arguments with variable
62+
$options = ['priority' => 100];
63+
$eventManager->on('Model.beforeFind', $handler, $options);
64+
}
65+
}
66+
67+
?>
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\MethodCall\EventManagerOnRector;
5+
use Rector\Config\RectorConfig;
6+
7+
return static function (RectorConfig $rectorConfig): void {
8+
$rectorConfig->rule(EventManagerOnRector::class);
9+
};

0 commit comments

Comments
 (0)