Skip to content

Commit 17bd644

Browse files
authored
[code-quality] Add TypeNullableEntityFromDocblockRector to add safe types to ddoctrine entities (#459)
1 parent 034ffe7 commit 17bd644

12 files changed

Lines changed: 622 additions & 15 deletions

File tree

config/sets/doctrine-code-quality.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Rector\Doctrine\CodeQuality\Rector\Property\CorrectDefaultTypesOnEntityPropertyRector;
1010
use Rector\Doctrine\CodeQuality\Rector\Property\TypedPropertyFromColumnTypeRector;
1111
use Rector\Doctrine\CodeQuality\Rector\Property\TypedPropertyFromToOneRelationTypeRector;
12+
use Rector\Doctrine\TypedCollections\Rector\Class_\CompleteReturnDocblockFromToManyRector;
1213
use Rector\Transform\Rector\Attribute\AttributeKeyToClassConstFetchRector;
1314
use Rector\Transform\ValueObject\AttributeKeyToClassConstFetch;
1415

@@ -22,6 +23,7 @@
2223
// typed properties in entities from annotations/attributes
2324
TypedPropertyFromColumnTypeRector::class,
2425
TypedPropertyFromToOneRelationTypeRector::class,
26+
CompleteReturnDocblockFromToManyRector::class,
2527

2628
// annotations generics
2729
AddAnnotationToRepositoryRector::class,
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
namespace Rector\Doctrine\Tests\CodeQuality\Rector\Class_\TypeNullableEntityFromDocblockRector\Fixture;
4+
5+
use Doctrine\ORM\Mapping as ORM;
6+
7+
#[ORM\Entity]
8+
class AttributeEntity
9+
{
10+
/**
11+
* @var string
12+
*/
13+
#[ORM\Id]
14+
#[ORM\Column(type: 'string')]
15+
#[ORM\GeneratedValue]
16+
private $name;
17+
18+
19+
/**
20+
* @return string
21+
*/
22+
public function getName()
23+
{
24+
return $this->name;
25+
}
26+
27+
/**
28+
* @param string $name
29+
*/
30+
public function setName($name): void
31+
{
32+
$this->name = $name;
33+
}
34+
}
35+
36+
37+
?>
38+
-----
39+
<?php
40+
41+
namespace Rector\Doctrine\Tests\CodeQuality\Rector\Class_\TypeNullableEntityFromDocblockRector\Fixture;
42+
43+
use Doctrine\ORM\Mapping as ORM;
44+
45+
#[ORM\Entity]
46+
class AttributeEntity
47+
{
48+
#[ORM\Id]
49+
#[ORM\Column(type: 'string')]
50+
#[ORM\GeneratedValue]
51+
private ?string $name = null;
52+
53+
54+
public function getName(): ?string
55+
{
56+
return $this->name;
57+
}
58+
59+
public function setName(?string $name): void
60+
{
61+
$this->name = $name;
62+
}
63+
}
64+
65+
66+
?>
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
namespace Rector\Doctrine\Tests\CodeQuality\Rector\Class_\TypeNullableEntityFromDocblockRector\Fixture;
4+
5+
use Doctrine\ORM\Mapping as ORM;
6+
7+
/**
8+
* @ORM\Entity()
9+
*/
10+
class DocblockEntity
11+
{
12+
/**
13+
* @var string
14+
* @ORM\Id
15+
* @ORM\Column(type="string")
16+
* @ORM\GeneratedValue
17+
*/
18+
private $name;
19+
20+
21+
/**
22+
* @return string
23+
*/
24+
public function getName()
25+
{
26+
return $this->name;
27+
}
28+
29+
/**
30+
* @param string $name
31+
*/
32+
public function setName($name): void
33+
{
34+
$this->name = $name;
35+
}
36+
}
37+
38+
39+
?>
40+
-----
41+
<?php
42+
43+
namespace Rector\Doctrine\Tests\CodeQuality\Rector\Class_\TypeNullableEntityFromDocblockRector\Fixture;
44+
45+
use Doctrine\ORM\Mapping as ORM;
46+
47+
/**
48+
* @ORM\Entity()
49+
*/
50+
class DocblockEntity
51+
{
52+
/**
53+
* @ORM\Id
54+
* @ORM\Column(type="string")
55+
* @ORM\GeneratedValue
56+
*/
57+
private ?string $name = null;
58+
59+
60+
public function getName(): ?string
61+
{
62+
return $this->name;
63+
}
64+
65+
public function setName(?string $name): void
66+
{
67+
$this->name = $name;
68+
}
69+
}
70+
71+
72+
?>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace Rector\Doctrine\Tests\CodeQuality\Rector\Class_\TypeNullableEntityFromDocblockRector\Fixture;
4+
5+
use Doctrine\ORM\Mapping as ORM;
6+
7+
#[ORM\Entity]
8+
class SkipUnknownPropertyType
9+
{
10+
#[ORM\Id]
11+
#[ORM\GeneratedValue]
12+
private $name;
13+
14+
15+
/**
16+
* @return string
17+
*/
18+
public function getName()
19+
{
20+
return $this->name;
21+
}
22+
23+
/**
24+
* @param string $name
25+
*/
26+
public function setName($name): void
27+
{
28+
$this->name = $name;
29+
}
30+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
namespace Rector\Doctrine\Tests\CodeQuality\Rector\Class_\TypeNullableEntityFromDocblockRector\Fixture;
4+
5+
use Doctrine\ORM\Mapping as ORM;
6+
7+
#[ORM\Entity]
8+
class UseColumnType
9+
{
10+
#[ORM\Id]
11+
#[ORM\Column(type: 'string')]
12+
#[ORM\GeneratedValue]
13+
private $name;
14+
15+
16+
/**
17+
* @return string
18+
*/
19+
public function getName()
20+
{
21+
return $this->name;
22+
}
23+
24+
/**
25+
* @param string $name
26+
*/
27+
public function setName($name): void
28+
{
29+
$this->name = $name;
30+
}
31+
}
32+
33+
34+
?>
35+
-----
36+
<?php
37+
38+
namespace Rector\Doctrine\Tests\CodeQuality\Rector\Class_\TypeNullableEntityFromDocblockRector\Fixture;
39+
40+
use Doctrine\ORM\Mapping as ORM;
41+
42+
#[ORM\Entity]
43+
class UseColumnType
44+
{
45+
#[ORM\Id]
46+
#[ORM\Column(type: 'string')]
47+
#[ORM\GeneratedValue]
48+
private ?string $name = null;
49+
50+
51+
public function getName(): ?string
52+
{
53+
return $this->name;
54+
}
55+
56+
public function setName(?string $name): void
57+
{
58+
$this->name = $name;
59+
}
60+
}
61+
62+
63+
?>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Doctrine\Tests\CodeQuality\Rector\Class_\TypeNullableEntityFromDocblockRector;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class TypeNullableEntityFromDocblockRectorTest extends AbstractRectorTestCase
12+
{
13+
#[DataProvider('provideData')]
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: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Rector\Config\RectorConfig;
6+
use Rector\Doctrine\CodeQuality\Rector\Class_\TypeNullableEntityFromDocblockRector;
7+
8+
return static function (RectorConfig $rectorConfig): void {
9+
$rectorConfig->rule(TypeNullableEntityFromDocblockRector::class);
10+
};
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Doctrine\CodeQuality\Helper;
6+
7+
use PhpParser\Node\Stmt\Class_;
8+
use PhpParser\Node\Stmt\ClassMethod;
9+
use Rector\TypeDeclaration\NodeAnalyzer\ClassMethodAndPropertyAnalyzer;
10+
11+
final readonly class SetterGetterFinder
12+
{
13+
public function __construct(
14+
private ClassMethodAndPropertyAnalyzer $classMethodAndPropertyAnalyzer
15+
) {
16+
}
17+
18+
public function findGetterClassMethod(Class_ $class, string $propertyName): ?ClassMethod
19+
{
20+
foreach ($class->getMethods() as $classMethod) {
21+
if (! $this->classMethodAndPropertyAnalyzer->hasPropertyFetchReturn($classMethod, $propertyName)) {
22+
continue;
23+
}
24+
25+
return $classMethod;
26+
}
27+
28+
return null;
29+
}
30+
31+
public function findSetterClassMethod(Class_ $class, string $propertyName): ?ClassMethod
32+
{
33+
foreach ($class->getMethods() as $classMethod) {
34+
if (! $this->classMethodAndPropertyAnalyzer->hasOnlyPropertyAssign($classMethod, $propertyName)) {
35+
continue;
36+
}
37+
38+
return $classMethod;
39+
}
40+
41+
return null;
42+
}
43+
}

0 commit comments

Comments
 (0)