Skip to content

Commit 8242649

Browse files
authored
Merge pull request #388 from cakephp/feature/translation-rector-6x
Add translation() => getOrCreateTranslation() rector rule for 6.x
2 parents 2533552 + c225d66 commit 8242649

6 files changed

Lines changed: 188 additions & 0 deletions

File tree

config/rector/sets/cakephp60.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Cake\Upgrade\Rector\Cake6\RemoveAssignmentFromVoidMethodRector;
88
use Cake\Upgrade\Rector\Cake6\ReplaceCommandArgsIoWithPropertiesRector;
99
use Cake\Upgrade\Rector\Cake6\RouteBuilderToCallbackFirstRector;
10+
use Cake\Upgrade\Rector\Cake6\TranslationToGetOrCreateTranslationRector;
1011
use Cake\Upgrade\Rector\Cake6\VoidMethod;
1112
use PHPStan\Type\ObjectType;
1213
use Rector\Config\RectorConfig;
@@ -31,6 +32,10 @@
3132
// RouteBuilder argument reordering
3233
$rectorConfig->rule(RouteBuilderToCallbackFirstRector::class);
3334

35+
// TranslateTrait::translation() became a pure getter, use getOrCreateTranslation() for create-on-access
36+
// @see https://github.com/cakephp/cakephp/pull/19251
37+
$rectorConfig->rule(TranslationToGetOrCreateTranslationRector::class);
38+
3439
// Changes related to the accessible => patchable rename
3540
$rectorConfig->ruleWithConfiguration(RenameMethodRector::class, [
3641
new MethodCallRename('Cake\ORM\Entity', 'setAccess', 'setPatchable'),
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Cake\Upgrade\Rector\Cake6;
5+
6+
use PhpParser\Node;
7+
use PhpParser\Node\Expr\MethodCall;
8+
use PhpParser\Node\Identifier;
9+
use PHPStan\Type\ObjectType;
10+
use Rector\Rector\AbstractRector;
11+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
12+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
13+
14+
/**
15+
* Renames translation() to getOrCreateTranslation() for entities using TranslateTrait.
16+
*
17+
* In CakePHP 6.0, translation() became a pure getter that returns null if no translation exists.
18+
* The old create-on-access behavior is now in getOrCreateTranslation().
19+
*
20+
* @see https://github.com/cakephp/cakephp/pull/19251
21+
*/
22+
final class TranslationToGetOrCreateTranslationRector extends AbstractRector
23+
{
24+
public function getRuleDefinition(): RuleDefinition
25+
{
26+
return new RuleDefinition(
27+
'Rename $entity->translation() to $entity->getOrCreateTranslation() to preserve create-on-access behavior',
28+
[
29+
new CodeSample(
30+
<<<'CODE_SAMPLE'
31+
$article->translation('fra');
32+
CODE_SAMPLE
33+
,
34+
<<<'CODE_SAMPLE'
35+
$article->getOrCreateTranslation('fra');
36+
CODE_SAMPLE,
37+
),
38+
],
39+
);
40+
}
41+
42+
/**
43+
* @return array<class-string<\PhpParser\Node>>
44+
*/
45+
public function getNodeTypes(): array
46+
{
47+
return [MethodCall::class];
48+
}
49+
50+
/**
51+
* @param \PhpParser\Node\Expr\MethodCall $node
52+
*/
53+
public function refactor(Node $node): ?Node
54+
{
55+
if (!$node->name instanceof Identifier) {
56+
return null;
57+
}
58+
59+
if ($node->name->toString() !== 'translation') {
60+
return null;
61+
}
62+
63+
if (!$this->isObjectType($node->var, new ObjectType('Cake\ORM\Entity'))) {
64+
return null;
65+
}
66+
67+
$node->name = new Identifier('getOrCreateTranslation');
68+
69+
return $node;
70+
}
71+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
namespace Cake\Upgrade\Test\TestCase\Rector\MethodCall\TranslationToGetOrCreateTranslationRector\Fixture;
4+
5+
use Cake\ORM\Entity;
6+
7+
class Article extends Entity
8+
{
9+
}
10+
11+
class ArticlesController
12+
{
13+
public function edit()
14+
{
15+
$article = new Article();
16+
17+
// Should transform: Entity->translation()
18+
$translation = $article->translation('fra');
19+
20+
return $article;
21+
}
22+
}
23+
24+
?>
25+
-----
26+
<?php
27+
28+
namespace Cake\Upgrade\Test\TestCase\Rector\MethodCall\TranslationToGetOrCreateTranslationRector\Fixture;
29+
30+
use Cake\ORM\Entity;
31+
32+
class Article extends Entity
33+
{
34+
}
35+
36+
class ArticlesController
37+
{
38+
public function edit()
39+
{
40+
$article = new Article();
41+
42+
// Should transform: Entity->translation()
43+
$translation = $article->getOrCreateTranslation('fra');
44+
45+
return $article;
46+
}
47+
}
48+
49+
?>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace Cake\Upgrade\Test\TestCase\Rector\MethodCall\TranslationToGetOrCreateTranslationRector\Fixture;
4+
5+
class SomeTranslationService
6+
{
7+
public function translation(string $lang): ?string
8+
{
9+
return null;
10+
}
11+
}
12+
13+
class SomeController
14+
{
15+
public function index()
16+
{
17+
$service = new SomeTranslationService();
18+
19+
// Should NOT transform: not an Entity subclass
20+
$result = $service->translation('fra');
21+
22+
return $result;
23+
}
24+
}
25+
26+
?>
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\TranslationToGetOrCreateTranslationRector;
5+
6+
use Iterator;
7+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
8+
9+
final class TranslationToGetOrCreateTranslationRectorTest 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\Cake6\TranslationToGetOrCreateTranslationRector;
5+
use Rector\Config\RectorConfig;
6+
7+
return static function (RectorConfig $rectorConfig): void {
8+
$rectorConfig->rule(TranslationToGetOrCreateTranslationRector::class);
9+
};

0 commit comments

Comments
 (0)