From d5a82d2a843d6838f99345698dc6ffb6ef5912c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jan 2024 21:34:48 +0000 Subject: [PATCH 1/5] Bump jinja2 from 3.1.2 to 3.1.3 in /Documentation Bumps [jinja2](https://github.com/pallets/jinja) from 3.1.2 to 3.1.3. - [Release notes](https://github.com/pallets/jinja/releases) - [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst) - [Commits](https://github.com/pallets/jinja/compare/3.1.2...3.1.3) --- updated-dependencies: - dependency-name: jinja2 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- Documentation/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/requirements.txt b/Documentation/requirements.txt index 5534297..54d5030 100644 --- a/Documentation/requirements.txt +++ b/Documentation/requirements.txt @@ -20,7 +20,7 @@ idna==3.4 # via requests imagesize==1.4.1 # via sphinx -jinja2==3.1.2 +jinja2==3.1.3 # via sphinx markupsafe==2.1.3 # via jinja2 From 14e37e0dfb684eeb267d48cd7146ce46e4683c3c Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Tue, 18 Jun 2024 16:05:39 +0200 Subject: [PATCH 2/5] TASK: Adjust to introduction of Shared\NodeAddress and new NodeUriBuilder --- .../DocumentUriPathProjectionHook.php | 38 +++++---------- Classes/Service/NodeRedirectService.php | 48 +++++++++---------- 2 files changed, 37 insertions(+), 49 deletions(-) diff --git a/Classes/CatchUpHook/DocumentUriPathProjectionHook.php b/Classes/CatchUpHook/DocumentUriPathProjectionHook.php index 4734cbb..d7a04e1 100644 --- a/Classes/CatchUpHook/DocumentUriPathProjectionHook.php +++ b/Classes/CatchUpHook/DocumentUriPathProjectionHook.php @@ -5,6 +5,7 @@ use Neos\ContentRepository\Core\Projection\CatchUpHookInterface; use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\EventStore\EventInterface; +use Neos\ContentRepository\Core\SharedModel\Node\NodeAddress; use Neos\EventStore\Model\EventEnvelope; use Neos\ContentRepository\Core\Feature\NodeModification\Event\NodePropertiesWereSet; use Neos\ContentRepository\Core\Feature\NodeMove\Event\NodeAggregateWasMoved; @@ -14,10 +15,7 @@ use Neos\Neos\FrontendRouting\Projection\DocumentUriPathFinder; use Neos\Neos\FrontendRouting\Projection\DocumentNodeInfo; use Neos\Neos\FrontendRouting\Exception\NodeNotFoundException; -use Neos\Neos\FrontendRouting\NodeAddress; -use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; -use Neos\Neos\FrontendRouting\NodeAddressFactory; final class DocumentUriPathProjectionHook implements CatchUpHookInterface { @@ -85,8 +83,7 @@ private function onBeforeNodeAggregateWasRemoved(NodeAggregateWasRemoved $event) $this->nodeRedirectService->appendAffectedNode( $node, - $this->getNodeAddress($event->contentStreamId, $dimensionSpacePoint, $node->getNodeAggregateId()), - $this->contentRepository->id + NodeAddress::create($this->contentRepository->id, $event->workspaceName, $dimensionSpacePoint, $node->getNodeAggregateId()) ); $this->documentNodeInfosBeforeRemoval[$dimensionSpacePoint->hash][] = $node; @@ -95,8 +92,7 @@ private function onBeforeNodeAggregateWasRemoved(NodeAggregateWasRemoved $event) function ($descendantOfNode) use ($event, $dimensionSpacePoint) { $this->nodeRedirectService->appendAffectedNode( $descendantOfNode, - $this->getNodeAddress($event->contentStreamId, $dimensionSpacePoint, $descendantOfNode->getNodeAggregateId()), - $this->contentRepository->id + NodeAddress::create($this->contentRepository->id, $event->workspaceName, $dimensionSpacePoint, $descendantOfNode->getNodeAggregateId()) ); $this->documentNodeInfosBeforeRemoval[$dimensionSpacePoint->hash][] = $descendantOfNode; }, @@ -144,6 +140,9 @@ private function onAfterNodePropertiesWereSet(NodePropertiesWereSet $event): voi ); } + /** + * @param \Closure(DocumentNodeInfo $nodeInfo, NodeAddress $nodeAddress):void $closure + */ private function handleNodePropertiesWereSet(NodePropertiesWereSet $event, \Closure $closure): void { if (!$this->isLiveContentStream($event->contentStreamId)) { @@ -162,13 +161,12 @@ private function handleNodePropertiesWereSet(NodePropertiesWereSet $event, \Clos continue; } - $closure($node, $this->getNodeAddress($event->contentStreamId, $affectedDimensionSpacePoint, $node->getNodeAggregateId()), $this->contentRepository->id); + $closure($node, NodeAddress::create($this->contentRepository->id, $event->workspaceName, $affectedDimensionSpacePoint, $node->getNodeAggregateId())); $descendantsOfNode = $this->getState()->getDescendantsOfNode($node); array_map(fn (DocumentNodeInfo $descendantOfNode) => $closure( $descendantOfNode, - $this->getNodeAddress($event->contentStreamId, $affectedDimensionSpacePoint, $descendantOfNode->getNodeAggregateId()), - $this->contentRepository->id + NodeAddress::create($this->contentRepository->id, $event->workspaceName, $affectedDimensionSpacePoint, $descendantOfNode->getNodeAggregateId()) ), iterator_to_array($descendantsOfNode)); } } @@ -189,6 +187,9 @@ private function onAfterNodeAggregateWasMoved(NodeAggregateWasMoved $event): voi ); } + /** + * @param \Closure(DocumentNodeInfo $nodeInfo, NodeAddress $nodeAddress):void $closure + */ private function handleNodeWasMoved(NodeAggregateWasMoved $event, \Closure $closure): void { if (!$this->isLiveContentStream($event->contentStreamId)) { @@ -202,13 +203,12 @@ private function handleNodeWasMoved(NodeAggregateWasMoved $event, \Closure $clos continue; } - $closure($node, $this->getNodeAddress($event->contentStreamId, $interdimensionalSibling->dimensionSpacePoint, $node->getNodeAggregateId()), $this->contentRepository->id); + $closure($node, NodeAddress::create($this->contentRepository->id, $event->workspaceName, $interdimensionalSibling->dimensionSpacePoint, $node->getNodeAggregateId())); $descendantsOfNode = $this->getState()->getDescendantsOfNode($node); array_map(fn (DocumentNodeInfo $descendantOfNode) => $closure( $descendantOfNode, - $this->getNodeAddress($event->contentStreamId, $interdimensionalSibling->dimensionSpacePoint, $descendantOfNode->getNodeAggregateId()), - $this->contentRepository->id + NodeAddress::create($this->contentRepository->id, $event->workspaceName, $interdimensionalSibling->dimensionSpacePoint, $descendantOfNode->getNodeAggregateId()) ), iterator_to_array($descendantsOfNode)); } } @@ -231,16 +231,4 @@ private function findNodeByIdAndDimensionSpacePointHash(NodeAggregateId $nodeAgg return null; } } - - protected function getNodeAddress( - ContentStreamId $contentStreamId, - DimensionSpacePoint $dimensionSpacePoint, - NodeAggregateId $nodeAggregateId, - ): NodeAddress { - return NodeAddressFactory::create($this->contentRepository)->createFromContentStreamIdAndDimensionSpacePointAndNodeAggregateId( - $contentStreamId, - $dimensionSpacePoint, - $nodeAggregateId - ); - } } diff --git a/Classes/Service/NodeRedirectService.php b/Classes/Service/NodeRedirectService.php index 724649b..d4e5ff8 100644 --- a/Classes/Service/NodeRedirectService.php +++ b/Classes/Service/NodeRedirectService.php @@ -13,12 +13,15 @@ * source code. */ +use Neos\ContentRepository\Core\SharedModel\Node\NodeAddress; use Neos\Flow\Annotations as Flow; use Neos\Flow\Persistence\PersistenceManagerInterface; use Neos\Neos\Domain\Model\Domain; use Neos\Neos\Domain\Model\SiteNodeName; use Neos\Neos\Domain\Repository\SiteRepository; +use Neos\Neos\FrontendRouting\NodeUriBuilderFactory; use Neos\RedirectHandler\Storage\RedirectStorageInterface; +use Psr\Http\Message\UriInterface; use Psr\Log\LoggerInterface; use Neos\ContentRepository\Core\NodeType\NodeType; use Neos\Neos\FrontendRouting\NodeUriBuilder; @@ -27,7 +30,6 @@ use Neos\Neos\FrontendRouting\SiteDetection\SiteDetectionResult; use Neos\Flow\Mvc\ActionRequest; use Neos\Neos\FrontendRouting\Projection\DocumentNodeInfo; -use Neos\Neos\FrontendRouting\NodeAddress; use Neos\ContentRepository\Core\NodeType\NodeTypeName; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use GuzzleHttp\Psr7\Uri; @@ -45,7 +47,13 @@ final class NodeRedirectService const STATUS_CODE_TYPE_REDIRECT = 'redirect'; const STATUS_CODE_TYPE_GONE = 'gone'; + /** + * @var array + */ private array $affectedNodes = []; + /** + * @var array> + */ private array $hostnamesRuntimeCache = []; #[Flow\Inject] @@ -76,25 +84,23 @@ final class NodeRedirectService protected array $restrictByNodeType = []; public function __construct( - protected RedirectStorageInterface $redirectStorage, - protected PersistenceManagerInterface $persistenceManager, - protected ContentRepositoryRegistry $contentRepositoryRegistry, - protected SiteRepository $siteRepository, + private readonly RedirectStorageInterface $redirectStorage, + private readonly PersistenceManagerInterface $persistenceManager, + private readonly ContentRepositoryRegistry $contentRepositoryRegistry, + private readonly SiteRepository $siteRepository, + private readonly NodeUriBuilderFactory $nodeUriBuilderFactory ) { } /** * Collects affected nodes before they got moved or removed. - * - * @throws \Neos\Flow\Http\Exception - * @throws \Neos\Flow\Mvc\Routing\Exception\MissingActionNameException */ - public function appendAffectedNode(DocumentNodeInfo $nodeInfo, NodeAddress $nodeAddress, ContentRepositoryId $contentRepositoryId): void + public function appendAffectedNode(DocumentNodeInfo $nodeInfo, NodeAddress $nodeAddress): void { try { - $this->affectedNodes[$this->createAffectedNodesKey($nodeInfo, $contentRepositoryId)] = [ + $this->affectedNodes[$this->createAffectedNodesKey($nodeInfo, $nodeAddress->contentRepositoryId)] = [ 'node' => $nodeInfo, - 'url' => $this->getNodeUriBuilder($nodeInfo->getSiteNodeName(), $contentRepositoryId)->uriFor($nodeAddress), + 'url' => $this->getNodeUriBuilder($nodeInfo->getSiteNodeName(), $nodeAddress->contentRepositoryId)->uriFor($nodeAddress), ]; } catch (NoMatchingRouteException $exception) { } @@ -102,31 +108,28 @@ public function appendAffectedNode(DocumentNodeInfo $nodeInfo, NodeAddress $node /** * Creates redirects for given node and uses the collected affected nodes to determine the source of the new redirect target. - * - * @throws \Neos\Flow\Http\Exception - * @throws \Neos\Flow\Mvc\Routing\Exception\MissingActionNameException */ - public function createRedirectForAffectedNode(DocumentNodeInfo $nodeInfo, NodeAddress $nodeAddress, ContentRepositoryId $contentRepositoryId): void + public function createRedirectForAffectedNode(DocumentNodeInfo $nodeInfo, NodeAddress $nodeAddress): void { if (!$this->enableAutomaticRedirects) { return; } - $affectedNode = $this->affectedNodes[$this->createAffectedNodesKey($nodeInfo, $contentRepositoryId)] ?? null; + $affectedNode = $this->affectedNodes[$this->createAffectedNodesKey($nodeInfo, $nodeAddress->contentRepositoryId)] ?? null; if ($affectedNode === null) { return; } - unset($this->affectedNodes[$this->createAffectedNodesKey($nodeInfo, $contentRepositoryId)]); + unset($this->affectedNodes[$this->createAffectedNodesKey($nodeInfo, $nodeAddress->contentRepositoryId)]); /** @var Uri $oldUri */ $oldUri = $affectedNode['url']; - $nodeType = $this->getNodeType($contentRepositoryId, $nodeInfo->getNodeTypeName()); + $nodeType = $this->getNodeType($nodeAddress->contentRepositoryId, $nodeInfo->getNodeTypeName()); if ($this->isRestrictedByNodeType($nodeType) || $this->isRestrictedByOldUri($oldUri->getPath())) { return; } try { - $newUri = $this->getNodeUriBuilder($nodeInfo->getSiteNodeName(), $contentRepositoryId)->uriFor($nodeAddress); + $newUri = $this->getNodeUriBuilder($nodeInfo->getSiteNodeName(), $nodeAddress->contentRepositoryId)->uriFor($nodeAddress); } catch (NoMatchingRouteException $exception) { // We can't build an uri for given node, so we can't create any redirect. E.g.: Node is disabled. return; @@ -179,15 +182,12 @@ protected function getNodeUriBuilder(SiteNodeName $siteNodeName, ContentReposito // Generate a custom request when the current request was triggered from CLI $baseUri = 'http://localhost'; - // Prevent `index.php` appearing in generated redirects - putenv('FLOW_REWRITEURLS=1'); - $httpRequest = new ServerRequest('POST', $baseUri); $httpRequest = (SiteDetectionResult::create($siteNodeName, $contentRepositoryId))->storeInRequest($httpRequest); $actionRequest = ActionRequest::fromHttpRequest($httpRequest); - return NodeUriBuilder::fromRequest($actionRequest); + return $this->nodeUriBuilderFactory->forActionRequest($actionRequest); } /** @@ -283,7 +283,7 @@ protected function isRestrictedByOldUri(string $oldUriPath): bool /** * Collects all hostnames from the Domain entries attached to the current site. - * @return array> + * @return list */ protected function getHostnames(SiteNodeName $siteNodeName): array { From 8c8f0cc6f63a030201f01cf16a7f70079149314a Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Mon, 24 Jun 2024 21:14:29 +0200 Subject: [PATCH 3/5] BUGFIX: Dont throw type error if NodeType does not exist anymore --- Classes/Service/NodeRedirectService.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Classes/Service/NodeRedirectService.php b/Classes/Service/NodeRedirectService.php index d4e5ff8..b9adde9 100644 --- a/Classes/Service/NodeRedirectService.php +++ b/Classes/Service/NodeRedirectService.php @@ -125,7 +125,7 @@ public function createRedirectForAffectedNode(DocumentNodeInfo $nodeInfo, NodeAd $oldUri = $affectedNode['url']; $nodeType = $this->getNodeType($nodeAddress->contentRepositoryId, $nodeInfo->getNodeTypeName()); - if ($this->isRestrictedByNodeType($nodeType) || $this->isRestrictedByOldUri($oldUri->getPath())) { + if (!$nodeType || $this->isRestrictedByNodeType($nodeType) || $this->isRestrictedByOldUri($oldUri->getPath())) { return; } try { @@ -158,7 +158,7 @@ public function createRedirectForRemovedAffectedNode(DocumentNodeInfo $nodeInfo, $oldUri = $affectedNode['url']; $nodeType = $this->getNodeType($contentRepositoryId, $nodeInfo->getNodeTypeName()); - if ($this->isRestrictedByNodeType($nodeType) || $this->isRestrictedByOldUri($oldUri->getPath())) { + if (!$nodeType || $this->isRestrictedByNodeType($nodeType) || $this->isRestrictedByOldUri($oldUri->getPath())) { return; } @@ -167,7 +167,7 @@ public function createRedirectForRemovedAffectedNode(DocumentNodeInfo $nodeInfo, $this->persistenceManager->persistAll(); } - protected function getNodeType(ContentRepositoryId $contentRepositoryId, NodeTypeName $nodeTypeName): NodeType + protected function getNodeType(ContentRepositoryId $contentRepositoryId, NodeTypeName $nodeTypeName): ?NodeType { return $this->contentRepositoryRegistry->get($contentRepositoryId)->getNodeTypeManager()->getNodeType($nodeTypeName); } From e38ca06175e39fb888da2898b1679bd8c6f53666 Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Mon, 24 Jun 2024 21:15:43 +0200 Subject: [PATCH 4/5] TASK: Also lint on php 8.3 --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ab22063..f9d693d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -20,7 +20,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['8.2'] + php-versions: ['8.2', '8.3'] services: mariadb: From f2fb3f34685e1af0e7e0fc2f7eb3dde251c33dd6 Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Mon, 24 Jun 2024 21:22:54 +0200 Subject: [PATCH 5/5] FEATURE: Introduce PHPStan level 8 for CI --- .github/workflows/tests.yml | 6 ++++++ Classes/CatchUpHook/DocumentUriPathProjectionHook.php | 2 +- composer.json | 1 + phpstan.neon.dist | 4 ++++ 4 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 phpstan.neon.dist diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f9d693d..aef12a3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -86,12 +86,18 @@ jobs: git -C ../${{ env.PACKAGE_FOLDER }} checkout -b build composer config repositories.package '{ "type": "path", "url": "../${{ env.PACKAGE_FOLDER }}", "options": { "symlink": false } }' composer require --no-update --no-interaction neos/redirecthandler-neosadapter:"dev-build as dev-${PACKAGE_TARGET_VERSION}" + composer require --dev --no-update --no-interaction phpstan/phpstan:^1.11 - name: Composer Install run: | cd ${NEOS_BASE_FOLDER} composer update --no-interaction --no-progress + - name: Linting + run: | + cd ${NEOS_BASE_FOLDER}/Packages/Application/Neos.RedirectHandler.NeosAdapter + composer run lint:phpstan + - name: Setup Flow configuration run: | cd ${NEOS_BASE_FOLDER} diff --git a/Classes/CatchUpHook/DocumentUriPathProjectionHook.php b/Classes/CatchUpHook/DocumentUriPathProjectionHook.php index d7a04e1..445a8d4 100644 --- a/Classes/CatchUpHook/DocumentUriPathProjectionHook.php +++ b/Classes/CatchUpHook/DocumentUriPathProjectionHook.php @@ -161,7 +161,7 @@ private function handleNodePropertiesWereSet(NodePropertiesWereSet $event, \Clos continue; } - $closure($node, NodeAddress::create($this->contentRepository->id, $event->workspaceName, $affectedDimensionSpacePoint, $node->getNodeAggregateId())); + $closure($node, NodeAddress::create($this->contentRepository->id, $event->workspaceName, $affectedDimensionSpacePoint, $node->getNodeAggregateId())); $descendantsOfNode = $this->getState()->getDescendantsOfNode($node); array_map(fn (DocumentNodeInfo $descendantOfNode) => $closure( diff --git a/composer.json b/composer.json index e428b87..b6b96e9 100644 --- a/composer.json +++ b/composer.json @@ -10,6 +10,7 @@ "neos/flow": "^9.0" }, "scripts": { + "lint:phpstan": "../../../bin/phpstan analyse", "test:behat-cli": "../../../bin/behat -f progress --strict --no-interaction", "test:behavioral:stop-on-failure": "@test:behat-cli -c Tests/Behavior/behat.yml.dist -vvv --stop-on-failure" }, diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000..d0cf7bd --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,4 @@ +parameters: + level: 8 + paths: + - Classes