From ae8894983c4bd8dd659fe22ef063b8e11577f341 Mon Sep 17 00:00:00 2001 From: Marco Sadowski Date: Fri, 15 Mar 2019 17:03:38 +0100 Subject: [PATCH 1/8] added new option resolutionHost With the resolutionHost option you can replace the complete hostname based on your content dimensions. --- .../SubdomainDimensionPresetDetector.php | 14 ++++++++++++-- .../TopLevelDomainDimensionPresetDetector.php | 11 ++++++++++- .../SubdomainDimensionPresetLinkProcessor.php | 6 +++++- .../TopLevelDomainDimensionPresetLinkProcessor.php | 5 ++++- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/Classes/Http/ContentDimensionDetection/SubdomainDimensionPresetDetector.php b/Classes/Http/ContentDimensionDetection/SubdomainDimensionPresetDetector.php index 83fe3e8..53586af 100644 --- a/Classes/Http/ContentDimensionDetection/SubdomainDimensionPresetDetector.php +++ b/Classes/Http/ContentDimensionDetection/SubdomainDimensionPresetDetector.php @@ -33,15 +33,25 @@ final class SubdomainDimensionPresetDetector implements ContentDimensionPresetDe public function detectPreset(string $dimensionName, array $presets, Http\Component\ComponentContext $componentContext, array $overrideOptions = null) { $host = $componentContext->getHttpRequest()->getUri()->getHost(); + $hostLength = mb_strlen($host); foreach ($presets as $availablePreset) { if (empty($availablePreset['resolutionValue'])) { // we leave the decision about how to handle empty values to the detection component continue; } + $valueLength = mb_strlen($availablePreset['resolutionValue']); + $value = mb_substr($host, 0, $valueLength); - if (mb_substr($host, 0, $valueLength) === $availablePreset['resolutionValue']) { - return $availablePreset; + if ($value === $availablePreset['resolutionValue']) { + if (array_key_exists('resolutionHost', $availablePreset)) { + $domain = mb_substr($host, $valueLength+1); + if ($domain === $availablePreset['resolutionHost']) { + return $availablePreset; + } + } else { + return $availablePreset; + } } } diff --git a/Classes/Http/ContentDimensionDetection/TopLevelDomainDimensionPresetDetector.php b/Classes/Http/ContentDimensionDetection/TopLevelDomainDimensionPresetDetector.php index d801ea5..4a18b0f 100644 --- a/Classes/Http/ContentDimensionDetection/TopLevelDomainDimensionPresetDetector.php +++ b/Classes/Http/ContentDimensionDetection/TopLevelDomainDimensionPresetDetector.php @@ -1,4 +1,5 @@ withHostPrefix($preset['resolutionValue'] ? $preset['resolutionValue'] . '.' : '', $prefixesToBeReplaced); + + if (array_key_exists('resolutionHost', $preset)) + return $uriConstraints->withHost($preset['resolutionValue'].'.'.$preset['resolutionHost']); + else + return $uriConstraints->withHostPrefix($preset['resolutionValue'] ? $preset['resolutionValue'] . '.' : '', $prefixesToBeReplaced); } } diff --git a/Classes/Http/ContentDimensionLinking/TopLevelDomainDimensionPresetLinkProcessor.php b/Classes/Http/ContentDimensionLinking/TopLevelDomainDimensionPresetLinkProcessor.php index 115d0d3..562af90 100644 --- a/Classes/Http/ContentDimensionLinking/TopLevelDomainDimensionPresetLinkProcessor.php +++ b/Classes/Http/ContentDimensionLinking/TopLevelDomainDimensionPresetLinkProcessor.php @@ -38,6 +38,9 @@ public function processUriConstraints( $hostSuffixesToBeReplaced[] = '.' . $availablePreset['resolutionValue']; } - return $uriConstraints->withHostSuffix('.' . $preset['resolutionValue'], $hostSuffixesToBeReplaced); + if (array_key_exists('resolutionHost', $preset)) + return $uriConstraints->withHost($preset['resolutionHost']); + else + return $uriConstraints->withHostSuffix('.' . $preset['resolutionValue'], $hostSuffixesToBeReplaced); } } From b3b34f714491b31dea738ed59a175d77167e5072 Mon Sep 17 00:00:00 2001 From: Marco Sadowski Date: Fri, 15 Mar 2019 17:31:31 +0100 Subject: [PATCH 2/8] edited docuentation and renamed it for github --- .gitignore | 3 +- Documentation/index.rst | 261 ---------------------------------------- readme.md | 260 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 261 insertions(+), 263 deletions(-) delete mode 100644 Documentation/index.rst create mode 100644 readme.md diff --git a/.gitignore b/.gitignore index 1874088..5509140 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -Documentation/* -!Documentation/*.rst +*.DS_Store diff --git a/Documentation/index.rst b/Documentation/index.rst deleted file mode 100644 index b4ed965..0000000 --- a/Documentation/index.rst +++ /dev/null @@ -1,261 +0,0 @@ -======================================== -Flowpack Neos Content Dimension Resolver -======================================== - -Introduction -============ - -For a general overview over content dimension, please refer to the respective sections in the Neos manual. - -This package enhances the default capabilities of detecting and linking to dimension presets by providing both new -features and extension points. - -Dimension Configuration -======================= - -The available dimensions and presets can be configured via settings: - -.. code-block:: yaml - - Neos: - ContentRepository: - contentDimensions: - - # Content dimension "language" serves for translation of content into different languages. Its value specifies - # the language or language variant by means of a locale. - 'language': - # The default dimension that is applied when creating nodes without specifying a dimension - default: 'mul_ZZ' - # The default preset to use if no URI segment was given when resolving languages in the router - defaultPreset: 'all' - label: 'Language' - icon: 'icon-language' - presets: - 'all': - label: 'All languages' - values: ['mul_ZZ'] - resolutionValue: 'all' - # Example for additional languages: - - 'en_GB': - label: 'English (Great Britain)' - values: ['en_GB', 'en_ZZ', 'mul_ZZ'] - resolutionValue: 'gb' - 'de': - label: 'German (Germany)' - values: ['de_DE', 'de_ZZ', 'mul_ZZ'] - resolutionValue: 'de' - -.. note:: - The ``uriSegment`` configuration option provided by default via Neos is still supported but disencouraged. - -Preset resolution -================= - -Using this package, content dimension presets can be resolved in different ways additional to the "classic" way of using an URI path segment. -Thus further configuration and implementation options have been added. - -The dimension resolver comes with three basic `resolution modes` which can be combined arbitrarily and configured individually. - -URI path segment based resolution ---------------------------------- - -The default resolution mode is ``uriPathSegment``. As by default in previous versions, it operates on an additional path segment, -e.g. ``https://domain.tld/{language}_{market}/home.html``. These are the configuration options available: - -.. code-block:: yaml - - Neos: - ContentRepository: - contentDimensions: - 'market': - resolution: - mode: 'uriPathSegment' - options: - # The offset defines the dimension's position in the path segment. Offset 1 means this is the second part. - # This allows for market being the second uriPath part although it's the primary dimension. - offset: 1 - 'language': - resolution: - mode: 'uriPathSegment' - options: - # Offset 0 means this is the first part. - offset: 0 - Flowpack: - Neos: - DimensionResolver: - contentDimensions: - resolution: - # Delimiter to separate values if multiple dimension are present - uriPathSegmentDelimiter: '-' - -With the given configuration, URIs will be resolved like ``domain.tld/{language}-{market}/home.html`` - -.. note:: - An arbitrary number of dimensions can be resolved via uriPathSegment. - The other way around, as long as no content dimensions resolved via uriPathSegment are defined, URIs will not contain any prefix. - -The default preset can have an empty `resolutionValue` value. The following example will lead to URLs that do not contain -`en` if the `en_US` preset is active, but will show the `resolutionValue` for other languages that are defined as well: - -.. code-block:: yaml - - Neos: - ContentRepository: - contentDimensions: - - 'language': - label: 'Language' - icon: 'icon-language' - default: 'en_US' - defaultPreset: 'en_US' - resolution: - mode: 'uriPathSegment' - presets: - 'en_US': - label: 'English (US)' - values: ['en_US'] - resolutionValue: '' - -The only limitation is that all resolution values must be unique across all dimensions that are resolved via uriPathSegment. -If you need non-unique resolution values, you can switch support for non-empty dimensions off: - -.. code-block:: yaml - - Neos: - Neos: - routing: - supportEmptySegmentForDimensions: FALSE - -Subdomain based resolution --------------------------- - -Another resolution mode is ``subdomain``. This mode extracts information from the first part of the host and adds it respectively -when generating URIs. - -.. code-block:: yaml - - Neos: - ContentRepository: - contentDimensions: - 'language': - default: 'en' - defaultPreset: 'en' - resolution: - mode: 'subdomain' - options: - # true means that if no preset can be detected, the default one will be used. - # Also when rendering new links, no subdomain will be added for the default preset - allowEmptyValue: true - presets: - 'en_GB': - label: 'English' - values: ['en'] - resolutionValue: 'en' - 'de': - label: 'German (Germany)' - values: ['de_DE'] - resolutionValue: 'de' - -With the given configuration, URIs will be resolved like ``{language}.domain.tld/home.html`` - -.. note:: - Only one dimension can be resolved via subdomain. - -Top level domain based resolution ---------------------------------- - -The final resolution mode is ``topLevelDomain``. This modes extracts information from the last part of the host and adds it respectively -when generating URIs. - -.. code-block:: yaml - - Neos: - ContentRepository: - contentDimensions: - 'market': - default: 'eu' - defaultPreset: 'eu' - resolution: - mode: 'topLevelDomain' - presets: - 'EU': - label: 'European Union' - values: ['EU'] - resolutionValue: 'eu' - 'GB': - label: 'Great Britain' - values: ['GB'] - resolutionValue: 'co.uk' - 'DE': - label: 'Germany' - values: ['DE', 'EU'] - resolutionValue: 'de' - -With the given configuration, URIs will be resolved like ``domain.{market}/home.html`` - -.. note:: - Only one dimension can be resolved via top level domain. - -Custom resolution ------------------ - -There are planned extension points in place to support custom implementations in case the basic ones do not suffice. - -Defining custom resolution components -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Each resolution mode is defined by two components: An implementation of ``Neos\Neos\Http\ContentDimensionDetection\ContentDimensionPresetDetectorInterface`` -to extract the preset from an HTTP request and an implementation of ``Neos\Neos\Http\ContentDimensionLinking\ContentDimensionPresetLinkProcessorInterface`` -for post processing links matching the given dimension presets. - -These can be implemented and configured individually per dimension: - -.. code-block:: yaml - - Neos: - ContentRepository: - contentDimensions: - weather: - detectionComponent: - implementationClassName: 'My\Package\Http\ContentDimensionDetection\WeatherDimensionPresetDetector' - linkProcessorComponent: - implementationClassName: 'My\Package\Http\ContentDimensionLinking\WeatherDimensionPresetLinkProcessor' - -If your custom preset resolution components do not affect the URI, you can use the ``Flowpack\Neos\DimensionResolver\Http\ContentDimensionLinking\NullDimensionPresetLinkProcessor`` -implementation as the link processor. - -.. note:: - If you want to replace implementations of one of the basic resolution modes, you can do it this way, too. - -Completely replacing resolution behaviour -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The described configuration and extension points assume that all dimension presets can be resolved independently. -There may be more complex situations though, where the resolution of one dimension depends on the result of the resolution of another. -As an example, think of a subdomain (language) and top level domain (market) based scenario where you want to support ``domain.fr``, -``domain.de``, ``de.domain.ch``, ``fr.domain.ch`` and ``it.domain.ch``. Although you can define the subdomain as optional, -the default language depends on the market: ``domain.de`` should be resolved to default language ``de`` and ``domain.fr`` -should be resolved to default language ``fr``. -Those complex scenarios are better served using individual implementations than complex configuration efforts. - -To enable developers to deal with this in a nice way, there are predefined ways to deal with both detection and link processing. - -Detection is done via an HTTP component that can be replaced via configuration: - -.. code-block:: yaml - - Neos: - Flow: - http: - chain: - preprocess: - chain: - detectContentSubgraph: - component: Flowpack\Neos\DimensionResolver\Http\DetectContentSubgraphComponent - -Link processing is done by the ``Flowpack\Neos\DimensionResolver\Http\ContentSubgraphUriProcessorInterface``. To introduce your custom behaviour, -implement the interface and declare it in ``Objects.yaml`` as usual in Flow. - -.. note:: - Please refer to the default implementations for further hints and ideas on how to implement resolution. diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..c78efd4 --- /dev/null +++ b/readme.md @@ -0,0 +1,260 @@ +# Flowpack Neos Content Dimension Resolver + +## Introduction + +For a general overview over content dimension, please refer to the respective sections in the Neos manual. + +This package enhances the default capabilities of detecting and linking to dimension presets by providing both new +features and extension points. + +## Dimension Configuration + +The available dimensions and presets can be configured via settings: + +``` + Neos: + ContentRepository: + contentDimensions: + + # Content dimension "language" serves for translation of content into different languages. Its value specifies + # the language or language variant by means of a locale. + 'language': + # The default dimension that is applied when creating nodes without specifying a dimension + default: 'mul_ZZ' + # The default preset to use if no URI segment was given when resolving languages in the router + defaultPreset: 'all' + label: 'Language' + icon: 'icon-language' + presets: + 'all': + label: 'All languages' + values: ['mul_ZZ'] + resolutionValue: 'all' + # Example for additional languages: + + 'en_GB': + label: 'English (Great Britain)' + values: ['en_GB', 'en_ZZ', 'mul_ZZ'] + resolutionValue: 'gb' + 'de': + label: 'German (Germany)' + values: ['de_DE', 'de_ZZ', 'mul_ZZ'] + resolutionValue: 'de' +``` + +>The `uriSegment` configuration option provided by default via Neos is still supported but disencouraged. + +## Preset resolution + +Using this package, content dimension presets can be resolved in different ways additional to the "classic" way of using an URI path segment. +Thus further configuration and implementation options have been added. + +The dimension resolver comes with three basic `resolution modes` which can be combined arbitrarily and configured individually. + +### URI path segment based resolution + +The default resolution mode is `uriPathSegment`. As by default in previous versions, it operates on an additional path segment, +e.g. `https://domain.tld/{language}_{market}/home.html`. These are the configuration options available: + +``` +Neos: + ContentRepository: + contentDimensions: + 'market': + resolution: + mode: 'uriPathSegment' + options: + # The offset defines the dimension's position in the path segment. Offset 1 means this is the second part. + # This allows for market being the second uriPath part although it's the primary dimension. + offset: 1 + 'language': + resolution: + mode: 'uriPathSegment' + options: + # Offset 0 means this is the first part. + offset: 0 +Flowpack: + Neos: + DimensionResolver: + contentDimensions: + resolution: + # Delimiter to separate values if multiple dimension are present + uriPathSegmentDelimiter: '-' +``` + +With the given configuration, URIs will be resolved like ``domain.tld/{language}-{market}/home.html`` + +>An arbitrary number of dimensions can be resolved via uriPathSegment. +The other way around, as long as no content dimensions resolved via uriPathSegment are defined, URIs will not contain any prefix. + +The default preset can have an empty `resolutionValue` value. The following example will lead to URLs that do not contain +`en` if the `en_US` preset is active, but will show the `resolutionValue` for other languages that are defined as well: + +``` +Neos: + ContentRepository: + contentDimensions: + + 'language': + label: 'Language' + icon: 'icon-language' + default: 'en_US' + defaultPreset: 'en_US' + resolution: + mode: 'uriPathSegment' + presets: + 'en_US': + label: 'English (US)' + values: ['en_US'] + resolutionValue: '' +``` + +The only limitation is that all resolution values must be unique across all dimensions that are resolved via uriPathSegment. +If you need non-unique resolution values, you can switch support for non-empty dimensions off: + +``` +Neos: + Neos: + routing: + supportEmptySegmentForDimensions: FALSE +``` + +### Subdomain based resolution + +Another resolution mode is `subdomain`. This mode extracts information from the first part of the host and adds it respectively +when generating URIs. + +``` +Neos: + ContentRepository: + contentDimensions: + 'language': + default: 'en' + defaultPreset: 'en' + resolution: + mode: 'subdomain' + options: + # true means that if no preset can be detected, the default one will be used. + # Also when rendering new links, no subdomain will be added for the default preset + allowEmptyValue: true + presets: + 'en_GB': + label: 'English' + values: ['en'] + resolutionValue: 'en' + 'de': + label: 'German (Germany)' + values: ['de_DE'] + resolutionValue: 'de' +``` + +With the given configuration, URIs will be resolved like `{language}.domain.tld/home.html` + +>Only one dimension can be resolved via subdomain. + +### Top level domain based resolution + +The final resolution mode is `topLevelDomain`. This modes extracts information from the last part of the host and adds it respectively +when generating URIs. + +``` +Neos: + ContentRepository: + contentDimensions: + 'market': + default: 'eu' + defaultPreset: 'eu' + resolution: + mode: 'topLevelDomain' + presets: + 'EU': + label: 'European Union' + values: ['EU'] + resolutionValue: 'eu' + 'GB': + label: 'Great Britain' + values: ['GB'] + resolutionValue: 'co.uk' + 'DE': + label: 'Germany' + values: ['DE', 'EU'] + resolutionValue: 'de' +``` +With the given configuration, URIs will be resolved like `domain.{market}/home.html` + +>Only one dimension can be resolved via top level domain. + +## Additionaly: Hostname based resolution + +You can also change the behaviour based on the hostname. You can use it on every resolution mode additonaly. You just need to add the option `resolutionHost` to your presets. Here a example how it looks like if you use the `topLevelDomain` mode: + +``` +presets: + 'EU': + label: 'European Union' + values: ['EU'] + resolutionHost: 'example.eu' + resolutionValue: 'eu' +``` + +With the given configuration, URIs will be resolved like `{resolutionHost}/home.html`. +If you use the option with the `subdomain` mode it will be resolved like `{resolutionValue}.{resolutionHost}/home.html`. + + +## Custom resolution + +There are planned extension points in place to support custom implementations in case the basic ones do not suffice. + +### Defining custom resolution components + +Each resolution mode is defined by two components: An implementation of `Neos\Neos\Http\ContentDimensionDetection\ContentDimensionPresetDetectorInterface` +to extract the preset from an HTTP request and an implementation of `Neos\Neos\Http\ContentDimensionLinking\ContentDimensionPresetLinkProcessorInterface` +for post processing links matching the given dimension presets. + +These can be implemented and configured individually per dimension: + +``` +Neos: + ContentRepository: + contentDimensions: + weather: + detectionComponent: + implementationClassName: 'My\Package\Http\ContentDimensionDetection\WeatherDimensionPresetDetector' + linkProcessorComponent: + implementationClassName: 'My\Package\Http\ContentDimensionLinking\WeatherDimensionPresetLinkProcessor' +``` + +If your custom preset resolution components do not affect the URI, you can use the `Flowpack\Neos\DimensionResolver\Http\ContentDimensionLinking\NullDimensionPresetLinkProcessor` +implementation as the link processor. + +>If you want to replace implementations of one of the basic resolution modes, you can do it this way, too. + +### Completely replacing resolution behaviour + +The described configuration and extension points assume that all dimension presets can be resolved independently. +There may be more complex situations though, where the resolution of one dimension depends on the result of the resolution of another. +As an example, think of a subdomain (language) and top level domain (market) based scenario where you want to support ``domain.fr``, +``domain.de``, ``de.domain.ch``, ``fr.domain.ch`` and ``it.domain.ch``. Although you can define the subdomain as optional, +the default language depends on the market: ``domain.de`` should be resolved to default language ``de`` and ``domain.fr`` +should be resolved to default language ``fr``. +Those complex scenarios are better served using individual implementations than complex configuration efforts. + +To enable developers to deal with this in a nice way, there are predefined ways to deal with both detection and link processing. + +Detection is done via an HTTP component that can be replaced via configuration: + +``` +Neos: + Flow: + http: + chain: + preprocess: + chain: + detectContentSubgraph: + component: Flowpack\Neos\DimensionResolver\Http\DetectContentSubgraphComponent +``` + +Link processing is done by the `Flowpack\Neos\DimensionResolver\Http\ContentSubgraphUriProcessorInterface`. To introduce your custom behaviour, +implement the interface and declare it in ``Objects.yaml`` as usual in Flow. + +>Please refer to the default implementations for further hints and ideas on how to implement resolution. From 8b536bdd22a1c093f3b74f9ed93da3752aea32d6 Mon Sep 17 00:00:00 2001 From: Marco Sadowski Date: Fri, 15 Mar 2019 17:54:15 +0100 Subject: [PATCH 3/8] added missing Syntax highlighting in readme file --- readme.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/readme.md b/readme.md index c78efd4..80b35d2 100644 --- a/readme.md +++ b/readme.md @@ -11,7 +11,7 @@ features and extension points. The available dimensions and presets can be configured via settings: -``` +```yaml Neos: ContentRepository: contentDimensions: @@ -56,7 +56,7 @@ The dimension resolver comes with three basic `resolution modes` which can be co The default resolution mode is `uriPathSegment`. As by default in previous versions, it operates on an additional path segment, e.g. `https://domain.tld/{language}_{market}/home.html`. These are the configuration options available: -``` +```yaml Neos: ContentRepository: contentDimensions: @@ -90,7 +90,7 @@ The other way around, as long as no content dimensions resolved via uriPathSegme The default preset can have an empty `resolutionValue` value. The following example will lead to URLs that do not contain `en` if the `en_US` preset is active, but will show the `resolutionValue` for other languages that are defined as well: -``` +```yaml Neos: ContentRepository: contentDimensions: @@ -112,7 +112,7 @@ Neos: The only limitation is that all resolution values must be unique across all dimensions that are resolved via uriPathSegment. If you need non-unique resolution values, you can switch support for non-empty dimensions off: -``` +```yaml Neos: Neos: routing: @@ -124,7 +124,7 @@ Neos: Another resolution mode is `subdomain`. This mode extracts information from the first part of the host and adds it respectively when generating URIs. -``` +```yaml Neos: ContentRepository: contentDimensions: @@ -157,7 +157,7 @@ With the given configuration, URIs will be resolved like `{language}.domain.tld/ The final resolution mode is `topLevelDomain`. This modes extracts information from the last part of the host and adds it respectively when generating URIs. -``` +```yaml Neos: ContentRepository: contentDimensions: @@ -188,7 +188,7 @@ With the given configuration, URIs will be resolved like `domain.{market}/home.h You can also change the behaviour based on the hostname. You can use it on every resolution mode additonaly. You just need to add the option `resolutionHost` to your presets. Here a example how it looks like if you use the `topLevelDomain` mode: -``` +```yaml presets: 'EU': label: 'European Union' @@ -213,7 +213,7 @@ for post processing links matching the given dimension presets. These can be implemented and configured individually per dimension: -``` +```yaml Neos: ContentRepository: contentDimensions: @@ -243,7 +243,7 @@ To enable developers to deal with this in a nice way, there are predefined ways Detection is done via an HTTP component that can be replaced via configuration: -``` +```yaml Neos: Flow: http: From 0d0ce6481344b20aa3c256a2ba197cbb6f581f45 Mon Sep 17 00:00:00 2001 From: Marco Sadowski Date: Wed, 12 Aug 2020 18:05:59 +0200 Subject: [PATCH 4/8] host can be used with uriPathSegment --- .../BackendUriDimensionPresetDetector.php | 0 .../ContentDimensionPresetDetectorInterface.php | 0 .../DimensionPresetDetectorResolver.php | 0 .../SubdomainDimensionPresetDetector.php | 0 .../TopLevelDomainDimensionPresetDetector.php | 16 +++++++--------- .../UriPathSegmentDimensionPresetDetector.php | 0 ...tentDimensionPresetLinkProcessorInterface.php | 0 .../DimensionPresetLinkProcessorResolver.php | 0 .../NullDimensionPresetLinkProcessor.php | 0 .../SubdomainDimensionPresetLinkProcessor.php | 0 ...opLevelDomainDimensionPresetLinkProcessor.php | 0 ...riPathSegmentDimensionPresetLinkProcessor.php | 5 ++++- Classes/Http/ContentDimensionResolutionMode.php | 0 Classes/Http/ContentSubgraphUriProcessor.php | 0 .../ContentSubgraphUriProcessorInterface.php | 0 Classes/Http/DetectContentSubgraphComponent.php | 2 +- .../InvalidDimensionPresetDetectorException.php | 0 ...alidDimensionPresetLinkProcessorException.php | 0 Classes/Routing/FrontendNodeRoutePartHandler.php | 0 19 files changed, 12 insertions(+), 11 deletions(-) mode change 100644 => 100755 Classes/Http/ContentDimensionDetection/BackendUriDimensionPresetDetector.php mode change 100644 => 100755 Classes/Http/ContentDimensionDetection/ContentDimensionPresetDetectorInterface.php mode change 100644 => 100755 Classes/Http/ContentDimensionDetection/DimensionPresetDetectorResolver.php mode change 100644 => 100755 Classes/Http/ContentDimensionDetection/SubdomainDimensionPresetDetector.php mode change 100644 => 100755 Classes/Http/ContentDimensionDetection/TopLevelDomainDimensionPresetDetector.php mode change 100644 => 100755 Classes/Http/ContentDimensionDetection/UriPathSegmentDimensionPresetDetector.php mode change 100644 => 100755 Classes/Http/ContentDimensionLinking/ContentDimensionPresetLinkProcessorInterface.php mode change 100644 => 100755 Classes/Http/ContentDimensionLinking/DimensionPresetLinkProcessorResolver.php mode change 100644 => 100755 Classes/Http/ContentDimensionLinking/NullDimensionPresetLinkProcessor.php mode change 100644 => 100755 Classes/Http/ContentDimensionLinking/SubdomainDimensionPresetLinkProcessor.php mode change 100644 => 100755 Classes/Http/ContentDimensionLinking/TopLevelDomainDimensionPresetLinkProcessor.php mode change 100644 => 100755 Classes/Http/ContentDimensionLinking/UriPathSegmentDimensionPresetLinkProcessor.php mode change 100644 => 100755 Classes/Http/ContentDimensionResolutionMode.php mode change 100644 => 100755 Classes/Http/ContentSubgraphUriProcessor.php mode change 100644 => 100755 Classes/Http/ContentSubgraphUriProcessorInterface.php mode change 100644 => 100755 Classes/Http/DetectContentSubgraphComponent.php mode change 100644 => 100755 Classes/Http/Exception/InvalidDimensionPresetDetectorException.php mode change 100644 => 100755 Classes/Http/Exception/InvalidDimensionPresetLinkProcessorException.php mode change 100644 => 100755 Classes/Routing/FrontendNodeRoutePartHandler.php diff --git a/Classes/Http/ContentDimensionDetection/BackendUriDimensionPresetDetector.php b/Classes/Http/ContentDimensionDetection/BackendUriDimensionPresetDetector.php old mode 100644 new mode 100755 diff --git a/Classes/Http/ContentDimensionDetection/ContentDimensionPresetDetectorInterface.php b/Classes/Http/ContentDimensionDetection/ContentDimensionPresetDetectorInterface.php old mode 100644 new mode 100755 diff --git a/Classes/Http/ContentDimensionDetection/DimensionPresetDetectorResolver.php b/Classes/Http/ContentDimensionDetection/DimensionPresetDetectorResolver.php old mode 100644 new mode 100755 diff --git a/Classes/Http/ContentDimensionDetection/SubdomainDimensionPresetDetector.php b/Classes/Http/ContentDimensionDetection/SubdomainDimensionPresetDetector.php old mode 100644 new mode 100755 diff --git a/Classes/Http/ContentDimensionDetection/TopLevelDomainDimensionPresetDetector.php b/Classes/Http/ContentDimensionDetection/TopLevelDomainDimensionPresetDetector.php old mode 100644 new mode 100755 index 4a18b0f..11aeee6 --- a/Classes/Http/ContentDimensionDetection/TopLevelDomainDimensionPresetDetector.php +++ b/Classes/Http/ContentDimensionDetection/TopLevelDomainDimensionPresetDetector.php @@ -36,18 +36,16 @@ public function detectPreset(string $dimensionName, array $presets, Http\Compone $host = $componentContext->getHttpRequest()->getUri()->getHost(); $hostLength = mb_strlen($host); foreach ($presets as $preset) { - $pivot = $hostLength - mb_strlen($preset['resolutionValue']); - - if (mb_substr($host, $pivot) === $preset['resolutionValue']) { - - if (array_key_exists('resolutionHost', $preset)) { - if ($host === $preset['resolutionHost']) { - return $preset; - } - } else { + if (array_key_exists('resolutionHost', $preset)) { + if ($host === $preset['resolutionHost']) { return $preset; } + } else { + $pivot = $hostLength - mb_strlen($preset['resolutionValue']); + if (mb_substr($host, $pivot) === $preset['resolutionValue']) { + return $preset; + } } } diff --git a/Classes/Http/ContentDimensionDetection/UriPathSegmentDimensionPresetDetector.php b/Classes/Http/ContentDimensionDetection/UriPathSegmentDimensionPresetDetector.php old mode 100644 new mode 100755 diff --git a/Classes/Http/ContentDimensionLinking/ContentDimensionPresetLinkProcessorInterface.php b/Classes/Http/ContentDimensionLinking/ContentDimensionPresetLinkProcessorInterface.php old mode 100644 new mode 100755 diff --git a/Classes/Http/ContentDimensionLinking/DimensionPresetLinkProcessorResolver.php b/Classes/Http/ContentDimensionLinking/DimensionPresetLinkProcessorResolver.php old mode 100644 new mode 100755 diff --git a/Classes/Http/ContentDimensionLinking/NullDimensionPresetLinkProcessor.php b/Classes/Http/ContentDimensionLinking/NullDimensionPresetLinkProcessor.php old mode 100644 new mode 100755 diff --git a/Classes/Http/ContentDimensionLinking/SubdomainDimensionPresetLinkProcessor.php b/Classes/Http/ContentDimensionLinking/SubdomainDimensionPresetLinkProcessor.php old mode 100644 new mode 100755 diff --git a/Classes/Http/ContentDimensionLinking/TopLevelDomainDimensionPresetLinkProcessor.php b/Classes/Http/ContentDimensionLinking/TopLevelDomainDimensionPresetLinkProcessor.php old mode 100644 new mode 100755 diff --git a/Classes/Http/ContentDimensionLinking/UriPathSegmentDimensionPresetLinkProcessor.php b/Classes/Http/ContentDimensionLinking/UriPathSegmentDimensionPresetLinkProcessor.php old mode 100644 new mode 100755 index 2301779..70a38c3 --- a/Classes/Http/ContentDimensionLinking/UriPathSegmentDimensionPresetLinkProcessor.php +++ b/Classes/Http/ContentDimensionLinking/UriPathSegmentDimensionPresetLinkProcessor.php @@ -46,6 +46,9 @@ public function processUriConstraints( $pathSegmentPart = $options['offset'] > 0 ? $options['delimiter'] : ''; $pathSegmentPart .= ($preset['resolutionValue'] ?? $preset['uriSegment']); - return $uriConstraints->withPathPrefix($pathSegmentPart . '/', true); + if (array_key_exists('resolutionHost', $preset)) + return $uriConstraints->withPathPrefix($pathSegmentPart . '/', true)->withHost($preset['resolutionHost']); + else + return $uriConstraints->withPathPrefix($pathSegmentPart . '/', true); } } diff --git a/Classes/Http/ContentDimensionResolutionMode.php b/Classes/Http/ContentDimensionResolutionMode.php old mode 100644 new mode 100755 diff --git a/Classes/Http/ContentSubgraphUriProcessor.php b/Classes/Http/ContentSubgraphUriProcessor.php old mode 100644 new mode 100755 diff --git a/Classes/Http/ContentSubgraphUriProcessorInterface.php b/Classes/Http/ContentSubgraphUriProcessorInterface.php old mode 100644 new mode 100755 diff --git a/Classes/Http/DetectContentSubgraphComponent.php b/Classes/Http/DetectContentSubgraphComponent.php old mode 100644 new mode 100755 index 4a005cd..9bbb543 --- a/Classes/Http/DetectContentSubgraphComponent.php +++ b/Classes/Http/DetectContentSubgraphComponent.php @@ -112,7 +112,7 @@ protected function detectDimensionSpacePoint(Http\Component\ComponentContext $co $resolutionMode = $presetConfiguration['resolution']['mode'] ?? ContentDimensionResolutionMode::RESOLUTION_MODE_URIPATHSEGMENT; if ($resolutionMode === ContentDimensionResolutionMode::RESOLUTION_MODE_URIPATHSEGMENT) { - $options['delimiter'] = $this->uriPathSegmentDelimiter; + if (!empty($this->uriPathSegmentDelimiter)) $options['delimiter'] = $this->uriPathSegmentDelimiter; } $preset = $detector->detectPreset($dimensionName, $presetConfiguration['presets'], $componentContext, $options); if ($preset && $resolutionMode === ContentDimensionResolutionMode::RESOLUTION_MODE_URIPATHSEGMENT) { diff --git a/Classes/Http/Exception/InvalidDimensionPresetDetectorException.php b/Classes/Http/Exception/InvalidDimensionPresetDetectorException.php old mode 100644 new mode 100755 diff --git a/Classes/Http/Exception/InvalidDimensionPresetLinkProcessorException.php b/Classes/Http/Exception/InvalidDimensionPresetLinkProcessorException.php old mode 100644 new mode 100755 diff --git a/Classes/Routing/FrontendNodeRoutePartHandler.php b/Classes/Routing/FrontendNodeRoutePartHandler.php old mode 100644 new mode 100755 From e5b05a73b8627e1fbc447120e948e50baf15084d Mon Sep 17 00:00:00 2001 From: Marco Sadowski Date: Tue, 5 Jan 2021 17:39:13 +0100 Subject: [PATCH 5/8] Switched to PSR-15 middleware for Neos 7.0 --- .../BackendUriDimensionPresetDetector.php | 8 +-- ...ontentDimensionPresetDetectorInterface.php | 6 +-- .../SubdomainDimensionPresetDetector.php | 8 +-- .../TopLevelDomainDimensionPresetDetector.php | 8 +-- .../UriPathSegmentDimensionPresetDetector.php | 8 +-- ...athSegmentDimensionPresetLinkProcessor.php | 5 +- .../Http/DetectContentSubgraphComponent.php | 51 ++++++++++++------- .../Routing/FrontendNodeRoutePartHandler.php | 6 +-- Configuration/Settings.yaml | 10 ++-- composer.json | 4 +- readme.md | 11 ++-- 11 files changed, 69 insertions(+), 56 deletions(-) diff --git a/Classes/Http/ContentDimensionDetection/BackendUriDimensionPresetDetector.php b/Classes/Http/ContentDimensionDetection/BackendUriDimensionPresetDetector.php index f6aa24b..765e2fc 100755 --- a/Classes/Http/ContentDimensionDetection/BackendUriDimensionPresetDetector.php +++ b/Classes/Http/ContentDimensionDetection/BackendUriDimensionPresetDetector.php @@ -12,7 +12,7 @@ */ use Neos\ContentRepository\Domain\Utility\NodePaths; -use Neos\Flow\Http; +use Psr\Http\Message\ServerRequestInterface; /** * Backend URI based dimension preset detector @@ -27,13 +27,13 @@ final class BackendUriDimensionPresetDetector implements ContentDimensionPresetD /** * @param string $dimensionName * @param array $presets - * @param Http\Component\ComponentContext $componentContext + * @param ServerRequestInterface $request * @param array|null $overrideOptions * @return array|null */ - public function detectPreset(string $dimensionName, array $presets, Http\Component\ComponentContext $componentContext, array $overrideOptions = null) + public function detectPreset(string $dimensionName, array $presets, ServerRequestInterface $request, array $overrideOptions = null) { - $path = $componentContext->getHttpRequest()->getUri()->getPath(); + $path = $request->getUri()->getPath(); $path = '/' . mb_substr($path, mb_strpos($path, '@')); if (mb_strpos($path, '.') !== false) { $path = mb_substr($path, 0, mb_strrpos($path, '.')); diff --git a/Classes/Http/ContentDimensionDetection/ContentDimensionPresetDetectorInterface.php b/Classes/Http/ContentDimensionDetection/ContentDimensionPresetDetectorInterface.php index 905f95a..c1f14d9 100755 --- a/Classes/Http/ContentDimensionDetection/ContentDimensionPresetDetectorInterface.php +++ b/Classes/Http/ContentDimensionDetection/ContentDimensionPresetDetectorInterface.php @@ -11,7 +11,7 @@ * source code. */ -use Neos\Flow\Http; +use Psr\Http\Message\ServerRequestInterface; /** * Interface to detect the current request's dimension preset @@ -31,9 +31,9 @@ interface ContentDimensionPresetDetectorInterface * * @param string $dimensionName * @param array $presets - * @param Http\Component\ComponentContext $componentContext + * @param ServerRequestInterface $request * @param array $overrideOptions * @return array|null */ - public function detectPreset(string $dimensionName, array $presets, Http\Component\ComponentContext $componentContext, array $overrideOptions = null); + public function detectPreset(string $dimensionName, array $presets, ServerRequestInterface $request, array $overrideOptions = null); } diff --git a/Classes/Http/ContentDimensionDetection/SubdomainDimensionPresetDetector.php b/Classes/Http/ContentDimensionDetection/SubdomainDimensionPresetDetector.php index 53586af..871e651 100755 --- a/Classes/Http/ContentDimensionDetection/SubdomainDimensionPresetDetector.php +++ b/Classes/Http/ContentDimensionDetection/SubdomainDimensionPresetDetector.php @@ -11,7 +11,7 @@ * source code. */ -use Neos\Flow\Http; +use Psr\Http\Message\ServerRequestInterface; /** * Subdomain based dimension preset detector @@ -26,13 +26,13 @@ final class SubdomainDimensionPresetDetector implements ContentDimensionPresetDe /** * @param string $dimensionName * @param array $presets - * @param Http\Component\ComponentContext $componentContext + * @param ServerRequestInterface $request * @param array|null $overrideOptions * @return array|null */ - public function detectPreset(string $dimensionName, array $presets, Http\Component\ComponentContext $componentContext, array $overrideOptions = null) + public function detectPreset(string $dimensionName, array $presets, ServerRequestInterface $request, array $overrideOptions = null) { - $host = $componentContext->getHttpRequest()->getUri()->getHost(); + $host = $request->getUri()->getHost(); $hostLength = mb_strlen($host); foreach ($presets as $availablePreset) { if (empty($availablePreset['resolutionValue'])) { diff --git a/Classes/Http/ContentDimensionDetection/TopLevelDomainDimensionPresetDetector.php b/Classes/Http/ContentDimensionDetection/TopLevelDomainDimensionPresetDetector.php index 11aeee6..10eaa78 100755 --- a/Classes/Http/ContentDimensionDetection/TopLevelDomainDimensionPresetDetector.php +++ b/Classes/Http/ContentDimensionDetection/TopLevelDomainDimensionPresetDetector.php @@ -12,7 +12,7 @@ * source code. */ -use Neos\Flow\Http; +use Psr\Http\Message\ServerRequestInterface; /** * Top level domain based dimension preset detector @@ -27,13 +27,13 @@ final class TopLevelDomainDimensionPresetDetector implements ContentDimensionPre /** * @param string $dimensionName * @param array $presets - * @param Http\Component\ComponentContext $componentContext + * @param ServerRequestInterface $request * @param array|null $overrideOptions * @return array|null */ - public function detectPreset(string $dimensionName, array $presets, Http\Component\ComponentContext $componentContext, array $overrideOptions = null) + public function detectPreset(string $dimensionName, array $presets, ServerRequestInterface $request, array $overrideOptions = null) { - $host = $componentContext->getHttpRequest()->getUri()->getHost(); + $host = $request->getUri()->getHost(); $hostLength = mb_strlen($host); foreach ($presets as $preset) { if (array_key_exists('resolutionHost', $preset)) { diff --git a/Classes/Http/ContentDimensionDetection/UriPathSegmentDimensionPresetDetector.php b/Classes/Http/ContentDimensionDetection/UriPathSegmentDimensionPresetDetector.php index 788830d..521061d 100755 --- a/Classes/Http/ContentDimensionDetection/UriPathSegmentDimensionPresetDetector.php +++ b/Classes/Http/ContentDimensionDetection/UriPathSegmentDimensionPresetDetector.php @@ -11,8 +11,8 @@ * source code. */ -use Neos\Flow\Http; use Neos\Utility\Arrays; +use Psr\Http\Message\ServerRequestInterface; /** * URI path segment based dimension preset detector @@ -30,14 +30,14 @@ final class UriPathSegmentDimensionPresetDetector implements ContentDimensionPre /** * @param string $dimensionName * @param array $presets - * @param Http\Component\ComponentContext $componentContext + * @param ServerRequestInterface $request * @param array|null $overrideOptions * @return array|null */ - public function detectPreset(string $dimensionName, array $presets, Http\Component\ComponentContext $componentContext, array $overrideOptions = null) + public function detectPreset(string $dimensionName, array $presets, ServerRequestInterface $request, array $overrideOptions = null) { $options = $overrideOptions ? Arrays::arrayMergeRecursiveOverrule($this->defaultOptions, $overrideOptions) : $this->defaultOptions; - $requestPath = $componentContext->getHttpRequest()->getUri()->getPath(); + $requestPath = $request->getUri()->getPath(); if (!empty($requestPath) && $requestPath !== '/' && mb_strpos($requestPath, '/') !== false) { $pathSegments = explode('/', ($requestPath)); diff --git a/Classes/Http/ContentDimensionLinking/UriPathSegmentDimensionPresetLinkProcessor.php b/Classes/Http/ContentDimensionLinking/UriPathSegmentDimensionPresetLinkProcessor.php index 70a38c3..e54d5a4 100755 --- a/Classes/Http/ContentDimensionLinking/UriPathSegmentDimensionPresetLinkProcessor.php +++ b/Classes/Http/ContentDimensionLinking/UriPathSegmentDimensionPresetLinkProcessor.php @@ -45,10 +45,9 @@ public function processUriConstraints( $options = $overrideOptions ? Arrays::arrayMergeRecursiveOverrule($this->defaultOptions, $overrideOptions) : $this->defaultOptions; $pathSegmentPart = $options['offset'] > 0 ? $options['delimiter'] : ''; $pathSegmentPart .= ($preset['resolutionValue'] ?? $preset['uriSegment']); - if (array_key_exists('resolutionHost', $preset)) - return $uriConstraints->withPathPrefix($pathSegmentPart . '/', true)->withHost($preset['resolutionHost']); + return $uriConstraints->withPathPrefix($pathSegmentPart, true)->withHost($preset['resolutionHost']); else - return $uriConstraints->withPathPrefix($pathSegmentPart . '/', true); + return $uriConstraints->withPathPrefix($pathSegmentPart, true); } } diff --git a/Classes/Http/DetectContentSubgraphComponent.php b/Classes/Http/DetectContentSubgraphComponent.php index 9bbb543..8836ae7 100755 --- a/Classes/Http/DetectContentSubgraphComponent.php +++ b/Classes/Http/DetectContentSubgraphComponent.php @@ -15,15 +15,21 @@ use Neos\ContentRepository\Domain\Service\ContextFactoryInterface; use Neos\ContentRepository\Domain\Utility\NodePaths; use Neos\Flow\Annotations as Flow; -use Neos\Flow\Http; + +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; + use Neos\Flow\Mvc\Routing\Dto\RouteParameters; -use Neos\Flow\Mvc\Routing\RoutingComponent; +use Neos\Flow\Http\ServerRequestAttributes; + use Flowpack\Neos\DimensionResolver\Http\ContentDimensionDetection\DimensionPresetDetectorResolver; /** * The HTTP component for detecting the requested dimension space point */ -final class DetectContentSubgraphComponent implements Http\Component\ComponentInterface +final class DetectContentSubgraphComponent implements MiddlewareInterface { /** * @Flow\Inject @@ -56,33 +62,42 @@ final class DetectContentSubgraphComponent implements Http\Component\ComponentIn protected $uriPathSegmentDelimiter; /** - * @param Http\Component\ComponentContext $componentContext + * @param ServerRequestInterface $request + * @param RequestHandlerInterface $next * @throws Exception\InvalidDimensionPresetDetectorException + * @return ResponseInterface */ - public function handle(Http\Component\ComponentContext $componentContext) + public function process(ServerRequestInterface $request, RequestHandlerInterface $next): ResponseInterface { $uriPathSegmentUsed = false; - $dimensionValues = $this->detectDimensionSpacePoint($componentContext, $uriPathSegmentUsed); - $workspaceName = $this->detectContentStream($componentContext); + $dimensionValues = $this->detectDimensionSpacePoint($request, $uriPathSegmentUsed); + $workspaceName = $this->detectContentStream($request); + + $existingParameters = $request->getAttribute(ServerRequestAttributes::ROUTING_PARAMETERS); + if ($existingParameters === null) { + $existingParameters = RouteParameters::createEmpty(); + } - $existingParameters = $componentContext->getParameter(RoutingComponent::class, 'parameters') ?? RouteParameters::createEmpty(); $parameters = $existingParameters ->withParameter('dimensionValues', json_encode($dimensionValues)) ->withParameter('workspaceName', $workspaceName) ->withParameter('uriPathSegmentUsed', $uriPathSegmentUsed); - $componentContext->setParameter(RoutingComponent::class, 'parameters', $parameters); + + $request = $request->withAttribute(ServerRequestAttributes::ROUTING_PARAMETERS, $parameters); + return $next->handle($request); } /** - * @param Http\Component\ComponentContext $componentContext + * @param ServerRequestInterface $request * @param bool $uriPathSegmentUsed * @return array * @throws Exception\InvalidDimensionPresetDetectorException */ - protected function detectDimensionSpacePoint(Http\Component\ComponentContext $componentContext, bool &$uriPathSegmentUsed): array + protected function detectDimensionSpacePoint(ServerRequestInterface $request, bool &$uriPathSegmentUsed): array { $coordinates = []; - $path = $componentContext->getHttpRequest()->getUri()->getPath(); + + $path = $request->getUri()->getPath(); $isContextPath = NodePaths::isContextPath($path); $backendUriDimensionPresetDetector = new ContentDimensionDetection\BackendUriDimensionPresetDetector(); @@ -96,12 +111,12 @@ protected function detectDimensionSpacePoint(Http\Component\ComponentContext $co $options['defaultPresetIdentifier'] = $presetConfiguration['defaultPreset']; if ($isContextPath) { - $preset = $backendUriDimensionPresetDetector->detectPreset($dimensionName, $presetConfiguration['presets'], $componentContext); + $preset = $backendUriDimensionPresetDetector->detectPreset($dimensionName, $presetConfiguration['presets'], $request); if ($preset) { $coordinates[$dimensionName] = $preset['values']; if ($detector instanceof ContentDimensionDetection\UriPathSegmentDimensionPresetDetector) { // we might have to remove the uri path segment anyway - $uriPathSegmentPreset = $detector->detectPreset($dimensionName, $presetConfiguration['presets'], $componentContext, $options); + $uriPathSegmentPreset = $detector->detectPreset($dimensionName, $presetConfiguration['presets'], $request, $options); if ($uriPathSegmentPreset) { $uriPathSegmentUsed = true; } @@ -114,7 +129,7 @@ protected function detectDimensionSpacePoint(Http\Component\ComponentContext $co if ($resolutionMode === ContentDimensionResolutionMode::RESOLUTION_MODE_URIPATHSEGMENT) { if (!empty($this->uriPathSegmentDelimiter)) $options['delimiter'] = $this->uriPathSegmentDelimiter; } - $preset = $detector->detectPreset($dimensionName, $presetConfiguration['presets'], $componentContext, $options); + $preset = $detector->detectPreset($dimensionName, $presetConfiguration['presets'], $request, $options); if ($preset && $resolutionMode === ContentDimensionResolutionMode::RESOLUTION_MODE_URIPATHSEGMENT) { $uriPathSegmentUsed = true; $uriPathSegmentOffset++; @@ -175,14 +190,14 @@ protected function generateOptionsFromLegacyConfiguration(array $presetConfigura } /** - * @param Http\Component\ComponentContext $componentContext + * @param ServerRequestInterface $request * @return string */ - protected function detectContentStream(Http\Component\ComponentContext $componentContext): string + protected function detectContentStream(ServerRequestInterface $request): string { $contentStreamIdentifier = 'live'; - $requestPath = $componentContext->getHttpRequest()->getUri()->getPath(); + $requestPath = $request->getUri()->getPath(); $requestPath = mb_substr($requestPath, mb_strrpos($requestPath, '/')); if ($requestPath !== '' && NodePaths::isContextPath($requestPath)) { try { diff --git a/Classes/Routing/FrontendNodeRoutePartHandler.php b/Classes/Routing/FrontendNodeRoutePartHandler.php index e0856f6..a055861 100755 --- a/Classes/Routing/FrontendNodeRoutePartHandler.php +++ b/Classes/Routing/FrontendNodeRoutePartHandler.php @@ -14,7 +14,7 @@ use Flowpack\Neos\DimensionResolver\Http; use Neos\Flow\Annotations as Flow; -use Neos\Flow\Log\PsrSystemLoggerInterface; +use Psr\Log\LoggerInterface; use Neos\Flow\Mvc\Routing\Dto\MatchResult; use Neos\Flow\Mvc\Routing\Dto\ResolveResult; use Neos\Flow\Mvc\Routing\Dto\RouteTags; @@ -37,8 +37,8 @@ class FrontendNodeRoutePartHandler extends DynamicRoutePart implements FrontendNodeRoutePartHandlerInterface { /** - * @Flow\Inject - * @var PsrSystemLoggerInterface + * @Flow\Inject(name="Neos.Flow:SystemLogger") + * @var LoggerInterface */ protected $systemLogger; diff --git a/Configuration/Settings.yaml b/Configuration/Settings.yaml index 01dae34..75c3bce 100644 --- a/Configuration/Settings.yaml +++ b/Configuration/Settings.yaml @@ -4,11 +4,11 @@ Flowpack: contentDimensions: resolution: uriPathSegmentDelimiter: '_' + Neos: Flow: http: - chain: - preprocess: - chain: - detectContentSubgraph: - component: Flowpack\Neos\DimensionResolver\Http\DetectContentSubgraphComponent + middlewares: + 'detectContentSubgraph': + position: 'before routing' + middleware: 'Flowpack\Neos\DimensionResolver\Http\DetectContentSubgraphComponent' diff --git a/composer.json b/composer.json index 51de055..1a1d496 100644 --- a/composer.json +++ b/composer.json @@ -4,8 +4,8 @@ "license": "GPL-3.0+", "description": "A support package for Neos CMS that allows for arbitrary content dimension resolution.", "require": { - "neos/neos": "~3.3.0||~4.0||~5.0||dev-master", - "neos/flow": "~4.3.0||~5.0||~6.0||dev-master" + "neos/neos": "~4.0||~5.0||~7.0||dev-master", + "neos/flow": "~5.0||~6.0||~7.0||dev-master" }, "autoload": { "psr-4": { diff --git a/readme.md b/readme.md index 80b35d2..bc0ee11 100644 --- a/readme.md +++ b/readme.md @@ -241,17 +241,16 @@ Those complex scenarios are better served using individual implementations than To enable developers to deal with this in a nice way, there are predefined ways to deal with both detection and link processing. -Detection is done via an HTTP component that can be replaced via configuration: +Detection is done via an HTTP Middleware that can be replaced via configuration: ```yaml Neos: Flow: http: - chain: - preprocess: - chain: - detectContentSubgraph: - component: Flowpack\Neos\DimensionResolver\Http\DetectContentSubgraphComponent + middlewares: + 'detectContentSubgraph': + position: 'before routing' + middleware: 'Flowpack\Neos\DimensionResolver\Http\DetectContentSubgraphComponent' ``` Link processing is done by the `Flowpack\Neos\DimensionResolver\Http\ContentSubgraphUriProcessorInterface`. To introduce your custom behaviour, From a0f2334fe0a58eaf5fab185cf8b4807206e30125 Mon Sep 17 00:00:00 2001 From: Marco Sadowski Date: Fri, 8 Jan 2021 15:32:01 +0100 Subject: [PATCH 6/8] renamed DetectContentSubgraphComponent --- .gitignore | 2 ++ Classes/Http/DetectContentSubgraphComponent.php | 2 +- Configuration/Settings.yaml | 2 +- .../Http/DetectContentSubgraphComponentTest.php | 12 ++++++------ .../DimensionPresetDetectorResolverTest.php | 2 +- .../DimensionPresetLinkProcessorResolverTest.php | 2 +- 6 files changed, 12 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 5509140..ee03875 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ *.DS_Store + +.idea/ diff --git a/Classes/Http/DetectContentSubgraphComponent.php b/Classes/Http/DetectContentSubgraphComponent.php index 8836ae7..753daf8 100755 --- a/Classes/Http/DetectContentSubgraphComponent.php +++ b/Classes/Http/DetectContentSubgraphComponent.php @@ -29,7 +29,7 @@ /** * The HTTP component for detecting the requested dimension space point */ -final class DetectContentSubgraphComponent implements MiddlewareInterface +final class DetectContentSubgraphMiddleware implements MiddlewareInterface { /** * @Flow\Inject diff --git a/Configuration/Settings.yaml b/Configuration/Settings.yaml index 75c3bce..6f09890 100644 --- a/Configuration/Settings.yaml +++ b/Configuration/Settings.yaml @@ -11,4 +11,4 @@ Neos: middlewares: 'detectContentSubgraph': position: 'before routing' - middleware: 'Flowpack\Neos\DimensionResolver\Http\DetectContentSubgraphComponent' + middleware: 'Flowpack\Neos\DimensionResolver\Http\DetectContentSubgraphMiddleware' diff --git a/Tests/Functional/Http/DetectContentSubgraphComponentTest.php b/Tests/Functional/Http/DetectContentSubgraphComponentTest.php index fc20d7a..158ea81 100644 --- a/Tests/Functional/Http/DetectContentSubgraphComponentTest.php +++ b/Tests/Functional/Http/DetectContentSubgraphComponentTest.php @@ -16,12 +16,12 @@ use Neos\Flow\Mvc\Routing\RoutingComponent; use Neos\Flow\Tests\FunctionalTestCase; use Flowpack\Neos\DimensionResolver\Http\ContentDimensionResolutionMode; -use Flowpack\Neos\DimensionResolver\Http\DetectContentSubgraphComponent; +use Flowpack\Neos\DimensionResolver\Http\DetectContentSubgraphMiddleware; /** * Test case for the BackendUriDimensionPresetDetector */ -class DetectContentSubgraphComponentTest extends FunctionalTestCase +class DetectContentSubgraphMiddlewareTest extends FunctionalTestCase { /** * @var array @@ -110,7 +110,7 @@ public function handleAddsCorrectSubgraphIdentityToComponentContextWithAllDimens $dimensionPresetSource = $this->objectManager->get(ContentDimensionPresetSourceInterface::class); $dimensionPresetSource->setConfiguration($this->dimensionPresets); - $detectSubgraphComponent = new DetectContentSubgraphComponent(); + $detectSubgraphComponent = new DetectContentSubgraphMiddleware(); $detectSubgraphComponent->handle($componentContext); /** @var RouteParameters $routeParameters */ @@ -135,7 +135,7 @@ public function handleAddsCorrectSubgraphIdentityToComponentContextWithAllDimens $dimensionPresetSource = $this->objectManager->get(ContentDimensionPresetSourceInterface::class); $dimensionPresetSource->setConfiguration($this->dimensionPresets); - $detectSubgraphComponent = new DetectContentSubgraphComponent(); + $detectSubgraphComponent = new DetectContentSubgraphMiddleware(); $this->inject($detectSubgraphComponent, 'uriPathSegmentDelimiter', '-'); @@ -162,7 +162,7 @@ public function handleAddsCorrectSubgraphIdentityToComponentContextWithMinimalDi $dimensionPresetSource = $this->objectManager->get(ContentDimensionPresetSourceInterface::class); $dimensionPresetSource->setConfiguration($this->dimensionPresets); - $detectSubgraphComponent = new DetectContentSubgraphComponent(); + $detectSubgraphComponent = new DetectContentSubgraphMiddleware(); $detectSubgraphComponent->handle($componentContext); /** @var RouteParameters $routeParameters */ @@ -188,7 +188,7 @@ public function handleAddsCorrectSubgraphIdentityToComponentContextWithDimension $dimensionPresetSource = $this->objectManager->get(ContentDimensionPresetSourceInterface::class); $dimensionPresetSource->setConfiguration($this->dimensionPresets); - $detectSubgraphComponent = new DetectContentSubgraphComponent(); + $detectSubgraphComponent = new DetectContentSubgraphMiddleware(); $detectSubgraphComponent->handle($componentContext); /** @var RouteParameters $routeParameters */ diff --git a/Tests/Unit/Http/ContentDimensionDetection/DimensionPresetDetectorResolverTest.php b/Tests/Unit/Http/ContentDimensionDetection/DimensionPresetDetectorResolverTest.php index 6c32481..9da3b1f 100644 --- a/Tests/Unit/Http/ContentDimensionDetection/DimensionPresetDetectorResolverTest.php +++ b/Tests/Unit/Http/ContentDimensionDetection/DimensionPresetDetectorResolverTest.php @@ -17,7 +17,7 @@ use Flowpack\Neos\DimensionResolver\Tests\Unit\Http\ContentDimensionDetection\Fixtures\ValidDummyDimensionPresetDetector; /** - * Test case for the DetectContentSubgraphComponent + * Test case for the DetectContentSubgraphMiddleware */ class DimensionPresetDetectorResolverTest extends UnitTestCase { diff --git a/Tests/Unit/Http/ContentDimensionLinking/DimensionPresetLinkProcessorResolverTest.php b/Tests/Unit/Http/ContentDimensionLinking/DimensionPresetLinkProcessorResolverTest.php index dab8fca..1b7ad36 100644 --- a/Tests/Unit/Http/ContentDimensionLinking/DimensionPresetLinkProcessorResolverTest.php +++ b/Tests/Unit/Http/ContentDimensionLinking/DimensionPresetLinkProcessorResolverTest.php @@ -17,7 +17,7 @@ use Flowpack\Neos\DimensionResolver\Tests\Unit\Http\ContentDimensionLinking\Fixtures\ValidDummyDimensionPresetLinkProcessor; /** - * Test case for the DetectContentSubgraphComponent + * Test case for the DetectContentSubgraphMiddleware */ class DimensionPresetLinkProcessorResolverTest extends UnitTestCase { From 5216ace7e4d68eca3c12fe05e8524c5920d9576f Mon Sep 17 00:00:00 2001 From: Marco Sadowski Date: Fri, 8 Jan 2021 15:33:27 +0100 Subject: [PATCH 7/8] renamed SubgraphMiddleware file --- ...tSubgraphComponent.php => DetectContentSubgraphMiddleware.php} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Classes/Http/{DetectContentSubgraphComponent.php => DetectContentSubgraphMiddleware.php} (100%) diff --git a/Classes/Http/DetectContentSubgraphComponent.php b/Classes/Http/DetectContentSubgraphMiddleware.php similarity index 100% rename from Classes/Http/DetectContentSubgraphComponent.php rename to Classes/Http/DetectContentSubgraphMiddleware.php From 6b601f3690913a8f6ef677fa221b679d69257b21 Mon Sep 17 00:00:00 2001 From: Marco Sadowski Date: Tue, 13 Jul 2021 12:52:14 +0200 Subject: [PATCH 8/8] Fix for PSR-7 v2 --- .../Http/DetectContentSubgraphMiddleware.php | 9 ++-- .../Routing/FrontendNodeRoutePartHandler.php | 41 ++++++++++++++++--- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/Classes/Http/DetectContentSubgraphMiddleware.php b/Classes/Http/DetectContentSubgraphMiddleware.php index 753daf8..d28aa29 100755 --- a/Classes/Http/DetectContentSubgraphMiddleware.php +++ b/Classes/Http/DetectContentSubgraphMiddleware.php @@ -72,16 +72,13 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface $uriPathSegmentUsed = false; $dimensionValues = $this->detectDimensionSpacePoint($request, $uriPathSegmentUsed); $workspaceName = $this->detectContentStream($request); - - $existingParameters = $request->getAttribute(ServerRequestAttributes::ROUTING_PARAMETERS); - if ($existingParameters === null) { - $existingParameters = RouteParameters::createEmpty(); - } + $existingParameters = $request->getAttribute(ServerRequestAttributes::ROUTING_PARAMETERS) ?? RouteParameters::createEmpty(); $parameters = $existingParameters ->withParameter('dimensionValues', json_encode($dimensionValues)) ->withParameter('workspaceName', $workspaceName) - ->withParameter('uriPathSegmentUsed', $uriPathSegmentUsed); + ->withParameter('uriPathSegmentUsed', $uriPathSegmentUsed) + ->withParameter('requestUriHost', $request->getUri()->getHost()); $request = $request->withAttribute(ServerRequestAttributes::ROUTING_PARAMETERS, $parameters); return $next->handle($request); diff --git a/Classes/Routing/FrontendNodeRoutePartHandler.php b/Classes/Routing/FrontendNodeRoutePartHandler.php index a055861..8c3c198 100755 --- a/Classes/Routing/FrontendNodeRoutePartHandler.php +++ b/Classes/Routing/FrontendNodeRoutePartHandler.php @@ -151,6 +151,7 @@ protected function matchValue($requestPath) $tagArray = [$contentContext->getWorkspace()->getName(), $node->getIdentifier()]; $parent = $node->getParent(); + while ($parent) { $tagArray[] = $parent->getIdentifier(); $parent = $parent->getParent(); @@ -197,8 +198,7 @@ protected function convertRequestPathToNode($requestPath) if ($requestPathWithoutContext === '') { $node = $siteNode; } else { - $relativeNodePath = $this->getRelativeNodePathByUriPathSegmentProperties($siteNode, $requestPathWithoutContext); - $node = ($relativeNodePath !== false) ? $siteNode->getNode($relativeNodePath) : null; + $node = $this->getNodeFromRequestPath($siteNode, $requestPathWithoutContext) ?? null; } if (!$node instanceof NodeInterface) { @@ -409,8 +409,7 @@ protected function resolveRoutePathForNode(NodeInterface $node) $nodeContextPathSuffix = ($workspaceName !== 'live') ? substr($nodeContextPath, strpos($nodeContextPath, '@')) : ''; $requestPath = $this->getRequestPathByNode($node); - - return trim($requestPath, '/') . $nodeContextPathSuffix; + return $requestPath . $nodeContextPathSuffix; } /** @@ -422,6 +421,7 @@ protected function resolveRoutePathForNode(NodeInterface $node) * * @param NodeInterface $siteNode The site node, used as a starting point while traversing the tree * @param string $relativeRequestPath The request path, relative to the site's root path + * @deprecated Use getNodeFromRequestPath() - return only the node * @return string * @throws \Neos\ContentRepository\Exception\NodeException */ @@ -448,6 +448,37 @@ protected function getRelativeNodePathByUriPathSegmentProperties(NodeInterface $ return implode('/', $relativeNodePathSegments); } + /** + * Return Node from RequestPath + * + * @param NodeInterface $siteNode The site node, used as a starting point while traversing the tree + * @param string $relativeRequestPath The request path, relative to the site's root path + * @return NodeInterface + * @throws \Neos\ContentRepository\Exception\NodeException + */ + protected function getNodeFromRequestPath(NodeInterface $siteNode, $relativeRequestPath) + { + $matchedNode = false; + $node = $siteNode; + + foreach (explode('/', $relativeRequestPath) as $pathSegment) { + $foundNodeInThisSegment = false; + foreach ($node->getChildNodes('Neos.Neos:Document') as $node) { + /** @var NodeInterface $node */ + if ($node->getProperty('uriPathSegment') === $pathSegment) { + $matchedNode = $node; + $foundNodeInThisSegment = true; + break; + } + } + if (!$foundNodeInThisSegment) { + return false; + } + } + + return $matchedNode; + } + /** * Renders a request path based on the "uriPathSegment" properties of the nodes leading to the given node. * @@ -482,6 +513,6 @@ protected function getRequestPathByNode(NodeInterface $node) $currentNode = $currentNode->getParent(); } - return implode('/', array_reverse($requestPathSegments)); + return '/' . implode('/', array_reverse($requestPathSegments)); } }