Skip to content

Commit 8547bdb

Browse files
authored
[Php81] Skip ReadOnlyPropertyRector on Entity id (#1379)
* [Php81] Skip ReadOnlyPropertyRector on Entity id * update fixture * Fixed 🎉 * clean up
1 parent df1391d commit 8547bdb

3 files changed

Lines changed: 156 additions & 1 deletion

File tree

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
namespace Rector\Tests\Php81\Rector\Property\ReadOnlyPropertyRector\Fixture;
4+
5+
use Ramsey\Uuid\UuidInterface;
6+
use Doctrine\ORM\Mapping as ORM;
7+
8+
/**
9+
* News
10+
*
11+
* @ORM\Table(name="news")
12+
* @ORM\Entity(repositoryClass="DoctrineFixtureDemo\Repository\NewsRepository")
13+
*/
14+
class News
15+
{
16+
/**
17+
* @var integer
18+
*
19+
* @ORM\Id()
20+
* @ORM\Column(type="uuid", unique=true)
21+
* @ORM\GeneratedValue(strategy="CUSTOM")
22+
* @ORM\CustomIdGenerator(class="Ramsey\Uuid\Doctrine\UuidGenerator")
23+
*/
24+
private UuidInterface $id;
25+
26+
/**
27+
* @var string
28+
*
29+
* @ORM\Column(name="title", type="string", length=50, nullable=false)
30+
*/
31+
private $title;
32+
33+
/**
34+
* Get id.
35+
*
36+
* @return string
37+
*/
38+
public function getId()
39+
{
40+
return (string) $this->id;
41+
}
42+
43+
/**
44+
* Set title.
45+
*
46+
* @param string $title
47+
*
48+
* @return self
49+
*/
50+
public function setTitle($title)
51+
{
52+
$this->title = $title;
53+
54+
return $this;
55+
}
56+
57+
/**
58+
* Get title.
59+
*
60+
* @return string
61+
*/
62+
public function getTitle()
63+
{
64+
return $this->title;
65+
}
66+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
namespace Rector\Tests\Php81\Rector\Property\ReadOnlyPropertyRector\Fixture;
4+
5+
use Ramsey\Uuid\UuidInterface;
6+
use Doctrine\ORM\Mapping as ORM;
7+
8+
/**
9+
* News
10+
*/
11+
#[ORM\Table(name: 'news')]
12+
#[ORM\Entity(repositoryClass: 'DoctrineFixtureDemo\Repository\NewsRepository')]
13+
class News2
14+
{
15+
/**
16+
* @var UuidInterface
17+
*/
18+
#[ORM\Id]
19+
#[ORM\Column(type: 'uuid', unique: true)]
20+
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
21+
#[ORM\CustomIdGenerator(class: 'Ramsey\Uuid\Doctrine\UuidGenerator')]
22+
private UuidInterface $id;
23+
24+
/**
25+
* @var string
26+
*/
27+
#[ORM\Column(name: 'title', type: 'string', length: 50, nullable: false)]
28+
private $title;
29+
30+
/**
31+
* Get id.
32+
*
33+
* @return string
34+
*/
35+
public function getId()
36+
{
37+
return (string) $this->id;
38+
}
39+
40+
/**
41+
* Set title.
42+
*
43+
* @param string $title
44+
*
45+
* @return self
46+
*/
47+
public function setTitle($title)
48+
{
49+
$this->title = $title;
50+
51+
return $this;
52+
}
53+
54+
/**
55+
* Get title.
56+
*
57+
* @return string
58+
*/
59+
public function getTitle()
60+
{
61+
return $this->title;
62+
}
63+
}

src/NodeManipulator/PropertyManipulator.php

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use PhpParser\Node\Expr\StaticCall;
1717
use PhpParser\Node\Expr\StaticPropertyFetch;
1818
use PhpParser\Node\Param;
19+
use PhpParser\Node\Stmt\Class_;
1920
use PhpParser\Node\Stmt\ClassLike;
2021
use PhpParser\Node\Stmt\ClassMethod;
2122
use PhpParser\Node\Stmt\Property;
@@ -27,6 +28,7 @@
2728
use Rector\Core\ValueObject\MethodName;
2829
use Rector\NodeNameResolver\NodeNameResolver;
2930
use Rector\NodeTypeResolver\Node\AttributeKey;
31+
use Rector\Php80\NodeAnalyzer\PhpAttributeAnalyzer;
3032
use Rector\ReadWrite\Guard\VariableToConstantGuard;
3133
use Rector\ReadWrite\NodeAnalyzer\ReadWritePropertyAnalyzer;
3234
use Symplify\PackageBuilder\Php\TypeChecker;
@@ -37,6 +39,14 @@
3739
*/
3840
final class PropertyManipulator
3941
{
42+
/**
43+
* @var string[]
44+
*/
45+
private const ALLOWED_NOT_READONLY_ANNOTATION_CLASS_OR_ATTRIBUTES = [
46+
'Doctrine\ORM\Mapping\Entity',
47+
'Doctrine\ORM\Mapping\Table',
48+
];
49+
4050
public function __construct(
4151
private AssignManipulator $assignManipulator,
4252
private BetterNodeFinder $betterNodeFinder,
@@ -46,7 +56,8 @@ public function __construct(
4656
private TypeChecker $typeChecker,
4757
private PropertyFetchFinder $propertyFetchFinder,
4858
private ReflectionResolver $reflectionResolver,
49-
private NodeNameResolver $nodeNameResolver
59+
private NodeNameResolver $nodeNameResolver,
60+
private PhpAttributeAnalyzer $phpAttributeAnalyzer
5061
) {
5162
}
5263

@@ -96,6 +107,21 @@ public function isPropertyUsedInReadContext(Property | Param $propertyOrPromoted
96107

97108
public function isPropertyChangeableExceptConstructor(Property | Param $propertyOrParam): bool
98109
{
110+
$class = $this->betterNodeFinder->findParentType($propertyOrParam, Class_::class);
111+
if ($class instanceof Class_) {
112+
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($class);
113+
if ($phpDocInfo->hasByAnnotationClasses(self::ALLOWED_NOT_READONLY_ANNOTATION_CLASS_OR_ATTRIBUTES)) {
114+
return true;
115+
}
116+
117+
if ($this->phpAttributeAnalyzer->hasPhpAttributes(
118+
$class,
119+
self::ALLOWED_NOT_READONLY_ANNOTATION_CLASS_OR_ATTRIBUTES
120+
)) {
121+
return true;
122+
}
123+
}
124+
99125
$propertyFetches = $this->propertyFetchFinder->findPrivatePropertyFetches($propertyOrParam);
100126

101127
foreach ($propertyFetches as $propertyFetch) {

0 commit comments

Comments
 (0)