From 683f33a52669445f247347eedb3e334e0eaab6bd Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Wed, 18 Sep 2019 08:44:17 +0200 Subject: [PATCH] [Doctrine] Add AlwaysInitializeUuidInEntityRector --- .../AlwaysInitializeUuidInEntityRector.php | 135 ++++++++++++++++++ ...AlwaysInitializeUuidInEntityRectorTest.php | 32 +++++ .../Fixture/add_uuid_init.php.inc | 45 ++++++ .../add_uuid_init_to_construct.php.inc | 52 +++++++ .../Fixture/skip_already_added.php.inc | 26 ++++ .../Source/UuidInterface.php | 8 ++ 6 files changed, 298 insertions(+) create mode 100644 packages/Doctrine/src/Rector/Class_/AlwaysInitializeUuidInEntityRector.php create mode 100644 packages/Doctrine/tests/Rector/Class_/AlwaysInitializeUuidInEntityRector/AlwaysInitializeUuidInEntityRectorTest.php create mode 100644 packages/Doctrine/tests/Rector/Class_/AlwaysInitializeUuidInEntityRector/Fixture/add_uuid_init.php.inc create mode 100644 packages/Doctrine/tests/Rector/Class_/AlwaysInitializeUuidInEntityRector/Fixture/add_uuid_init_to_construct.php.inc create mode 100644 packages/Doctrine/tests/Rector/Class_/AlwaysInitializeUuidInEntityRector/Fixture/skip_already_added.php.inc create mode 100644 packages/Doctrine/tests/Rector/Class_/AlwaysInitializeUuidInEntityRector/Source/UuidInterface.php diff --git a/packages/Doctrine/src/Rector/Class_/AlwaysInitializeUuidInEntityRector.php b/packages/Doctrine/src/Rector/Class_/AlwaysInitializeUuidInEntityRector.php new file mode 100644 index 000000000000..b0b173f54570 --- /dev/null +++ b/packages/Doctrine/src/Rector/Class_/AlwaysInitializeUuidInEntityRector.php @@ -0,0 +1,135 @@ +entityUuidNodeFactory = $entityUuidNodeFactory; + } + + public function getDefinition(): RectorDefinition + { + return new RectorDefinition('Add uuid initializion to all entities that misses it'); + } + + /** + * @return string[] + */ + public function getNodeTypes(): array + { + return [Class_::class]; + } + + /** + * @param Class_ $node + */ + public function refactor(Node $node): ?Node + { + if (! $this->isDoctrineEntityClass($node)) { + return null; + } + + $uuidProperty = $this->resolveUuidPropertyFromClass($node); + if ($uuidProperty === null) { + return null; + } + + $uuidPropertyName = $this->getName($uuidProperty); + if ($this->hasUuidInitAlreadyAdded($node, $uuidPropertyName)) { + return null; + } + + $constructClassMethod = $node->getMethod('__construct'); + if ($constructClassMethod === null) { + $constructClassMethod = $this->entityUuidNodeFactory->createConstructorWithUuidInitialization( + $node, + $uuidPropertyName + ); + $node->stmts = array_merge((array) $node->stmts, [$constructClassMethod]); + } else { + $assignExpression = $this->entityUuidNodeFactory->createUuidPropertyDefaultValueAssign($uuidPropertyName); + $constructClassMethod->stmts = array_merge([$assignExpression], (array) $constructClassMethod->stmts); + } + + return $node; + } + + private function resolveUuidPropertyFromClass(Class_ $class): ?Property + { + foreach ($class->getProperties() as $property) { + $propertyPhpDoc = $this->getPhpDocInfo($property); + if ($propertyPhpDoc === null) { + continue; + } + + $varType = $propertyPhpDoc->getVarType(); + if (! $varType instanceof ObjectType) { + continue; + } + + if (! Strings::contains($varType->getClassName(), 'UuidInterface')) { + continue; + } + + return $property; + } + + return null; + } + + private function hasUuidInitAlreadyAdded(Class_ $class, string $uuidPropertyName): bool + { + $constructClassMethod = $class->getMethod('__construct'); + if ($constructClassMethod === null) { + return false; + } + + return (bool) $this->betterNodeFinder->findFirst((array) $class->stmts, function (Node $node) use ( + $uuidPropertyName + ): bool { + if (! $node instanceof Assign) { + return false; + } + + if (! $node->expr instanceof StaticCall) { + return false; + } + + $staticCall = $node->expr; + if (! $this->isObjectType($staticCall->class, 'Ramsey\Uuid\Uuid')) { + return false; + } + + if (! $this->isName($staticCall->name, 'uuid4')) { + return false; + } + + if (! $this->isName($node->var, $uuidPropertyName)) { + return false; + } + + return true; + }); + } +} diff --git a/packages/Doctrine/tests/Rector/Class_/AlwaysInitializeUuidInEntityRector/AlwaysInitializeUuidInEntityRectorTest.php b/packages/Doctrine/tests/Rector/Class_/AlwaysInitializeUuidInEntityRector/AlwaysInitializeUuidInEntityRectorTest.php new file mode 100644 index 000000000000..9470cae90c09 --- /dev/null +++ b/packages/Doctrine/tests/Rector/Class_/AlwaysInitializeUuidInEntityRector/AlwaysInitializeUuidInEntityRectorTest.php @@ -0,0 +1,32 @@ +doTestFile($file); + } + + /** + * @return string[] + */ + public function provideDataForTest(): iterable + { + yield [__DIR__ . '/Fixture/add_uuid_init.php.inc']; + yield [__DIR__ . '/Fixture/add_uuid_init_to_construct.php.inc']; + yield [__DIR__ . '/Fixture/skip_already_added.php.inc']; + } + + protected function getRectorClass(): string + { + return AlwaysInitializeUuidInEntityRector::class; + } +} diff --git a/packages/Doctrine/tests/Rector/Class_/AlwaysInitializeUuidInEntityRector/Fixture/add_uuid_init.php.inc b/packages/Doctrine/tests/Rector/Class_/AlwaysInitializeUuidInEntityRector/Fixture/add_uuid_init.php.inc new file mode 100644 index 000000000000..4491da191937 --- /dev/null +++ b/packages/Doctrine/tests/Rector/Class_/AlwaysInitializeUuidInEntityRector/Fixture/add_uuid_init.php.inc @@ -0,0 +1,45 @@ + +----- +superUuid = \Ramsey\Uuid\Uuid::uuid4(); + } +} + +?> diff --git a/packages/Doctrine/tests/Rector/Class_/AlwaysInitializeUuidInEntityRector/Fixture/add_uuid_init_to_construct.php.inc b/packages/Doctrine/tests/Rector/Class_/AlwaysInitializeUuidInEntityRector/Fixture/add_uuid_init_to_construct.php.inc new file mode 100644 index 000000000000..b1d3134969c2 --- /dev/null +++ b/packages/Doctrine/tests/Rector/Class_/AlwaysInitializeUuidInEntityRector/Fixture/add_uuid_init_to_construct.php.inc @@ -0,0 +1,52 @@ + +----- +superUuid = \Ramsey\Uuid\Uuid::uuid4(); + $one = 2; + } +} + +?> diff --git a/packages/Doctrine/tests/Rector/Class_/AlwaysInitializeUuidInEntityRector/Fixture/skip_already_added.php.inc b/packages/Doctrine/tests/Rector/Class_/AlwaysInitializeUuidInEntityRector/Fixture/skip_already_added.php.inc new file mode 100644 index 000000000000..cb4ba9b8dfc6 --- /dev/null +++ b/packages/Doctrine/tests/Rector/Class_/AlwaysInitializeUuidInEntityRector/Fixture/skip_already_added.php.inc @@ -0,0 +1,26 @@ +superUuid = \Ramsey\Uuid\Uuid::uuid4(); + $one = 2; + } +} + +?> diff --git a/packages/Doctrine/tests/Rector/Class_/AlwaysInitializeUuidInEntityRector/Source/UuidInterface.php b/packages/Doctrine/tests/Rector/Class_/AlwaysInitializeUuidInEntityRector/Source/UuidInterface.php new file mode 100644 index 000000000000..e2c8bbb71cf3 --- /dev/null +++ b/packages/Doctrine/tests/Rector/Class_/AlwaysInitializeUuidInEntityRector/Source/UuidInterface.php @@ -0,0 +1,8 @@ +