From d5aa352021c6e1a1e085e7bfa2a823372cbf7b20 Mon Sep 17 00:00:00 2001 From: Denny Lubitz Date: Mon, 25 Nov 2024 16:30:53 +0100 Subject: [PATCH] FEATURE: Add migration for NodeSearchService --- config/set/contentrepository-90.php | 6 + docs/rules_overview.md | 138 +++++++++++++++++- .../Rules/NodeSearchServiceRector.php | 121 +++++++++++++++ .../Fixture/some_class.php.inc | 64 ++++++++ .../NodeSearchServiceRectorTest.php | 31 ++++ .../config/configured_rule.php | 12 ++ .../Fixture/node-search-service.php.inc | 66 +++++++++ 7 files changed, 434 insertions(+), 4 deletions(-) create mode 100644 src/ContentRepository90/Rules/NodeSearchServiceRector.php create mode 100644 tests/ContentRepository90/Rules/NodeSearchServiceRector/Fixture/some_class.php.inc create mode 100644 tests/ContentRepository90/Rules/NodeSearchServiceRector/NodeSearchServiceRectorTest.php create mode 100644 tests/ContentRepository90/Rules/NodeSearchServiceRector/config/configured_rule.php create mode 100644 tests/Sets/ContentRepository90/Fixture/node-search-service.php.inc diff --git a/config/set/contentrepository-90.php b/config/set/contentrepository-90.php index b3b6314..73e2ecc 100644 --- a/config/set/contentrepository-90.php +++ b/config/set/contentrepository-90.php @@ -51,6 +51,7 @@ use Neos\Rector\ContentRepository90\Rules\NodeIsHiddenInIndexRector; use Neos\Rector\ContentRepository90\Rules\NodeIsHiddenRector; use Neos\Rector\ContentRepository90\Rules\NodeLabelGeneratorRector; +use Neos\Rector\ContentRepository90\Rules\NodeSearchServiceRector; use Neos\Rector\ContentRepository90\Rules\NodeTypeAllowsGrandchildNodeTypeRector; use Neos\Rector\ContentRepository90\Rules\NodeTypeGetAutoCreatedChildNodesRector; use Neos\Rector\ContentRepository90\Rules\NodeTypeGetNameRector; @@ -389,6 +390,11 @@ // ContentDimensionCombinator::getAllAllowedCombinations $rectorConfig->rule(ContentDimensionCombinatorGetAllAllowedCombinationsRector::class); + /** + * Neos\Neos\Domain\Service\NodeSearchService + */ + $rectorConfig->rule(NodeSearchServiceRector::class); + /** * Neos\ContentRepository\Domain\Factory\NodeFactory diff --git a/docs/rules_overview.md b/docs/rules_overview.md index c869dc1..fef89e4 100644 --- a/docs/rules_overview.md +++ b/docs/rules_overview.md @@ -1,4 +1,4 @@ -# 61 Rules Overview +# 63 Rules Overview ## ContentDimensionCombinatorGetAllAllowedCombinationsRector @@ -1533,8 +1533,7 @@ return static function (RectorConfig $rectorConfig): void { public function run(NodeLegacyStub $node) { - $nodeType = $node->getNodeType(); -+ // TODO 9.0 migration: Make this code aware of multiple Content Repositories. -+ $contentRepository = $this->contentRepositoryRegistry->get(\Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId::fromString('default')); ++ $contentRepository = $this->contentRepositoryRegistry->get($node->contentRepositoryId); + $nodeType = $contentRepository->getNodeTypeManager()->getNodeType($node->nodeTypeName); } } @@ -1700,6 +1699,52 @@ return static function (RectorConfig $rectorConfig): void {
+## NodeSearchServiceRector + +`"NodeSearchService::findDescendantNodes()"` will be rewritten + +- class: [`Neos\Rector\ContentRepository90\Rules\NodeSearchServiceRector`](../src/ContentRepository90/Rules/NodeSearchServiceRector.php) + +```diff + nodeSearchService->findByProperties($term, $searchNodeTypes, $context, $node); ++ // TODO 9.0 migration: This could be a suitable replacement. Please check if all your requirements are still fulfilled. ++ $subgraph = $this->contentRepositoryRegistry->subgraphForNode($node); ++ $nodes = $subgraph->findDescendantNodes($node->aggregateId, \Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindDescendantNodesFilter::create(nodeTypes: \Neos\ContentRepository\Core\Projection\ContentGraph\Filter\NodeType\NodeTypeCriteria::create(\Neos\ContentRepository\Core\NodeType\NodeTypeNames::fromStringArray($searchNodeTypes), \Neos\ContentRepository\Core\NodeType\NodeTypeNames::createEmpty()), searchTerm: $term)); + } + + public function startingPointNodeIsNotGiven(Context $context) + { + $term = "term"; + $searchNodeTypes = []; +- $nodes = $this->nodeSearchService->findByProperties($term, $searchNodeTypes, $context); ++ // TODO 9.0 migration: The replacement needs a node as starting point for the search. Please provide a node, to make this replacement working. ++ $node = 'we-need-a-node-here'; ++ $subgraph = $this->contentRepositoryRegistry->subgraphForNode($node); ++ $nodes = $subgraph->findDescendantNodes($node->aggregateId, \Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindDescendantNodesFilter::create(nodeTypes: \Neos\ContentRepository\Core\Projection\ContentGraph\Filter\NodeType\NodeTypeCriteria::create(\Neos\ContentRepository\Core\NodeType\NodeTypeNames::fromStringArray($searchNodeTypes), \Neos\ContentRepository\Core\NodeType\NodeTypeNames::createEmpty()), searchTerm: $term)); + } + } +``` + +
+ ## NodeTypeAllowsGrandchildNodeTypeRector "$nodeType->allowsGrandchildNodeType($parentNodeName, `$nodeType)"` will be rewritten. @@ -1808,7 +1853,7 @@ return static function (RectorConfig $rectorConfig): void { $nodeName = NodeName::fromString('name'); $nodeType = $node->getNodeType(); - $type = $nodeType->getTypeOfAutoCreatedChildNode($nodeName); -+ // TODO 9.0 migration: Make this code aware of multiple Content Repositories. ++ // TODO 9.0 migration: Make this code aware of multiple Content Repositories. If you have a Node object around you can use $node->contentRepositoryId. + $contentRepository = $this->contentRepositoryRegistry->get(\Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId::fromString('default')); + $type = $contentRepository->getNodeTypeManager()->getNodeType($nodeType->tetheredNodeTypeDefinitions->get($nodeName)); } @@ -1984,6 +2029,91 @@ return static function (RectorConfig $rectorConfig): void {
+## SignalSlotToWarningCommentRector + +"Warning comments for various non-supported signals + +:wrench: **configure it!** + +- class: [`Neos\Rector\Generic\Rules\SignalSlotToWarningCommentRector`](../src/Generic/Rules/SignalSlotToWarningCommentRector.php) + +```php +extension('rectorConfig', [ + [ + 'class' => SignalSlotToWarningCommentRector::class, + 'configuration' => [ + new SignalSlotToWarningComment('PhpParser\Node', 'beforeMove', '!! This signal "beforeMove" on Node doesn\'t exist anymore'), + ], + ], + ]); +}; +``` + +↓ + +```diff + getSignalSlotDispatcher(); ++ // TODO 9.0 migration: Signal "beforeMove" doesn't exist anymore + ++ + $dispatcher->connect( + NodeLegacyStub::class, + 'beforeMove', + SomeOtherClass::class, + 'someMethod' + ); ++ // TODO 9.0 migration: Signal "afterMove" doesn't exist anymore ++ + + $dispatcher->connect( + 'Neos\Rector\ContentRepository90\Legacy\NodeLegacyStub', + 'afterMove', + SomeOtherClass::class, + 'someMethod' + ); + + $dispatcher->connect( + NodeLegacyStub::class, + 'otherMethod', + SomeOtherClass::class, + 'someMethod' + ); + + $dispatcher->connect( + OtherClass::class, + 'afterMove', + SomeOtherClass::class, + 'someMethod' + ); + } + } + + ?> +``` + +
+ ## ToStringToMethodCallOrPropertyFetchRector Turns defined code uses of `"__toString()"` method to specific method calls or property fetches. diff --git a/src/ContentRepository90/Rules/NodeSearchServiceRector.php b/src/ContentRepository90/Rules/NodeSearchServiceRector.php new file mode 100644 index 0000000..5f08ce9 --- /dev/null +++ b/src/ContentRepository90/Rules/NodeSearchServiceRector.php @@ -0,0 +1,121 @@ +> + */ + public function getNodeTypes(): array + { + return [\PhpParser\Node\Expr\MethodCall::class]; + } + + /** + * @param \PhpParser\Node\Expr\MethodCall $node + */ + public function refactor(Node $node): ?Node + { + assert($node instanceof Node\Expr\MethodCall); + + if (!$this->isObjectType($node->var, new ObjectType(\Neos\Neos\Domain\Service\NodeSearchService::class))) { + return null; + } + if (!$this->isName($node->name, 'findByProperties')) { + return null; + } + + if (!isset($node->args[3])) { + $nodeExpr = self::assign('node', new \PhpParser\Node\Scalar\String_('we-need-a-node-here')); + $nodeNode = $nodeExpr->expr->var; + + $this->nodesToAddCollector->addNodesBeforeNode( + [ + self::withTodoComment('The replacement needs a node as starting point for the search. Please provide a node, to make this replacement working.', $nodeExpr), + $subgraphNode = self::assign('subgraph', $this->this_contentRepositoryRegistry_subgraphForNode($nodeNode)), + ], + $node + ); + + } else { + $this->nodesToAddCollector->addNodesBeforeNode( + [ + self::withTodoComment('This could be a suitable replacement. Please check if all your requirements are still fulfilled.', + $subgraphNode = self::assign('subgraph', $this->this_contentRepositoryRegistry_subgraphForNode($node->args[3]->value)) + ) + ], + $node + + ); + $nodeNode = $node->args[3]->value; + + } + + return $this->nodeFactory->createMethodCall( + $subgraphNode->expr->var, + 'findDescendantNodes', + [ + $this->nodeFactory->createPropertyFetch( + $nodeNode, + 'aggregateId' + ), + $this->nodeFactory->createStaticCall( + \Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindDescendantNodesFilter::class, + 'create', + [ + 'nodeTypes' => $this->nodeFactory->createStaticCall( + \Neos\ContentRepository\Core\Projection\ContentGraph\Filter\NodeType\NodeTypeCriteria::class, + 'create', + [ + $this->nodeFactory->createStaticCall( + \Neos\ContentRepository\Core\NodeType\NodeTypeNames::class, + 'fromStringArray', + [ + $node->args[1]->value, + ] + ), + $this->nodeFactory->createStaticCall( + \Neos\ContentRepository\Core\NodeType\NodeTypeNames::class, + 'createEmpty', + ), + ] + ), + 'searchTerm' => $node->args[0]->value, + ] + ) + ] + ); + } +} + +/** + * \Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindDescendantNodesFilter::create( + * nodeTypes: \Neos\ContentRepository\Core\Projection\ContentGraph\Filter\NodeType\NodeTypeCriteria::create( + * \Neos\ContentRepository\Core\NodeType\NodeTypeNames::fromStringArray($searchNodeTypes), + * \Neos\ContentRepository\Core\NodeType\NodeTypeNames::createEmpty() + * ), + * searchTerm: $term + * ) + */ diff --git a/tests/ContentRepository90/Rules/NodeSearchServiceRector/Fixture/some_class.php.inc b/tests/ContentRepository90/Rules/NodeSearchServiceRector/Fixture/some_class.php.inc new file mode 100644 index 0000000..7ef9e5d --- /dev/null +++ b/tests/ContentRepository90/Rules/NodeSearchServiceRector/Fixture/some_class.php.inc @@ -0,0 +1,64 @@ +nodeSearchService->findByProperties($term, $searchNodeTypes, $context, $node); + } + + public function startingPointNodeIsNotGiven(Context $context) + { + $term = "term"; + $searchNodeTypes = []; + $nodes = $this->nodeSearchService->findByProperties($term, $searchNodeTypes, $context); + } +} + +----- +contentRepositoryRegistry->subgraphForNode($node); + $nodes = $subgraph->findDescendantNodes($node->aggregateId, \Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindDescendantNodesFilter::create(nodeTypes: \Neos\ContentRepository\Core\Projection\ContentGraph\Filter\NodeType\NodeTypeCriteria::create(\Neos\ContentRepository\Core\NodeType\NodeTypeNames::fromStringArray($searchNodeTypes), \Neos\ContentRepository\Core\NodeType\NodeTypeNames::createEmpty()), searchTerm: $term)); + } + + public function startingPointNodeIsNotGiven(Context $context) + { + $term = "term"; + $searchNodeTypes = []; + // TODO 9.0 migration: The replacement needs a node as starting point for the search. Please provide a node, to make this replacement working. + $node = 'we-need-a-node-here'; + $subgraph = $this->contentRepositoryRegistry->subgraphForNode($node); + $nodes = $subgraph->findDescendantNodes($node->aggregateId, \Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindDescendantNodesFilter::create(nodeTypes: \Neos\ContentRepository\Core\Projection\ContentGraph\Filter\NodeType\NodeTypeCriteria::create(\Neos\ContentRepository\Core\NodeType\NodeTypeNames::fromStringArray($searchNodeTypes), \Neos\ContentRepository\Core\NodeType\NodeTypeNames::createEmpty()), searchTerm: $term)); + } +} + diff --git a/tests/ContentRepository90/Rules/NodeSearchServiceRector/NodeSearchServiceRectorTest.php b/tests/ContentRepository90/Rules/NodeSearchServiceRector/NodeSearchServiceRectorTest.php new file mode 100644 index 0000000..45f47ab --- /dev/null +++ b/tests/ContentRepository90/Rules/NodeSearchServiceRector/NodeSearchServiceRectorTest.php @@ -0,0 +1,31 @@ +doTestFile($fileInfo); + } + + /** + * @return \Iterator + */ + public function provideData(): \Iterator + { + return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/tests/ContentRepository90/Rules/NodeSearchServiceRector/config/configured_rule.php b/tests/ContentRepository90/Rules/NodeSearchServiceRector/config/configured_rule.php new file mode 100644 index 0000000..0ef16f1 --- /dev/null +++ b/tests/ContentRepository90/Rules/NodeSearchServiceRector/config/configured_rule.php @@ -0,0 +1,12 @@ +rule(NodeSearchServiceRector::class); +}; diff --git a/tests/Sets/ContentRepository90/Fixture/node-search-service.php.inc b/tests/Sets/ContentRepository90/Fixture/node-search-service.php.inc new file mode 100644 index 0000000..e995dd5 --- /dev/null +++ b/tests/Sets/ContentRepository90/Fixture/node-search-service.php.inc @@ -0,0 +1,66 @@ +nodeSearchService->findByProperties($term, $searchNodeTypes, $context, $node); + } + + public function startingPointNodeIsNotGiven(Context $context) + { + $term = "term"; + $searchNodeTypes = []; + $nodes = $this->nodeSearchService->findByProperties($term, $searchNodeTypes, $context); + } +} + +----- +contentRepositoryRegistry->subgraphForNode($node); + $nodes = $subgraph->findDescendantNodes($node->aggregateId, \Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindDescendantNodesFilter::create(nodeTypes: \Neos\ContentRepository\Core\Projection\ContentGraph\Filter\NodeType\NodeTypeCriteria::create(\Neos\ContentRepository\Core\NodeType\NodeTypeNames::fromStringArray($searchNodeTypes), \Neos\ContentRepository\Core\NodeType\NodeTypeNames::createEmpty()), searchTerm: $term)); + } + + public function startingPointNodeIsNotGiven(\Neos\Rector\ContentRepository90\Legacy\LegacyContextStub $context) + { + $term = "term"; + $searchNodeTypes = []; + // TODO 9.0 migration: The replacement needs a node as starting point for the search. Please provide a node, to make this replacement working. + $node = 'we-need-a-node-here'; + $subgraph = $this->contentRepositoryRegistry->subgraphForNode($node); + $nodes = $subgraph->findDescendantNodes($node->aggregateId, \Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindDescendantNodesFilter::create(nodeTypes: \Neos\ContentRepository\Core\Projection\ContentGraph\Filter\NodeType\NodeTypeCriteria::create(\Neos\ContentRepository\Core\NodeType\NodeTypeNames::fromStringArray($searchNodeTypes), \Neos\ContentRepository\Core\NodeType\NodeTypeNames::createEmpty()), searchTerm: $term)); + } +} +