Bug #91530
closedEmpty optional arguments throws InvalidParameterException using the ExtbasePluginEnhancer
0%
Description
Hi,
we try to migrate our old realurl setup into the new routing configurations.
Now, when we use the ExtbasePluginEnhancer for optional/empty arguments it throws the InvalidParameterException in the Symfony UrlGenerator in not cached situations for links, which will be rendered by this ExtbasePluginEnhancer:
Parameter "tx_example_pi1__category" for route "tx_example_pi1_0" must match "[^/]++" ("" given) to generate a corresponding URL.
We tried different settings like default or requirements but nothing work.
The example url: https://example.com/index.php?id=1&tx_example_pi1[category]=
Our setup is the following:
routeEnhancers: Example: type: Extbase extension: Example plugin: Pi1 limitToPages: - 1 routes: - routePath: '/category/{category_slug}' _controller: 'Category::list' _arguments: category_slug: category aspects: category_slug: type: PersistedAliasMapper tableName: sys_category routeFieldName: slug
It must be said in advance, that the old behavior was using the trailing slash, so we integrate that behavior as a ForceAppendingSlashDecorator like the example here: https://stackoverflow.com/a/53144597
We fixed the issue through and new configuration and an override of the ExtbasePluginEnhancer.
New configuration:
routeEnhancers: Example: ... optionalArguments: - tx_example_pi1__category ...
Override ExtbasePluginEnhancer:
... use TYPO3\CMS\Core\Routing\Route; use TYPO3\CMS\Extbase\Routing\ExtbasePluginEnhancer as ExtbasePluginEnhancerCore; class ExtbasePluginEnhancer extends ExtbasePluginEnhancerCore { protected function verifyRequiredParameters(Route $route, array $parameters): bool { if (parent::verifyRequiredParameters($route, $parameters)) { if (is_array($this->configuration['optionalArguments'])) { $compiledRoute = $route->compile(); $deflatedParameters = $this->deflateParameters($route, $parameters); foreach($this->configuration['optionalArguments'] as $optionalArgument) { foreach ($compiledRoute->getPathVariables() as $pathVariable) { if ( $pathVariable == $optionalArgument && ( !isset($deflatedParameters[$optionalArgument]) || $deflatedParameters[$optionalArgument] == '' ) ) { return false; } } } } } return true; } }
Please investigate this. Thanks.
Updated by Oliver Hader over 4 years ago
- Status changed from New to Needs Feedback
I did not look into the custom implementation since I guess the scenario could have been solved either with route defauls
or a dedicated separate route.
defaults & requirements¶
Example: type: Extbase extension: Example plugin: Pi1 ... defaults: category_slug: '' requirements: # weakening the `.+` default requirement category_slug: '.*'
separare route¶
Example: type: Extbase extension: Example plugin: Pi1 routes: - routePath: '/category' _controller: 'Category::list' - routePath: '/category/{category_slug}' _controller: 'Category::list' _arguments: category_slug: category
Updated by Stefan Berger over 4 years ago
Hi Oliver,
thanks for your feedback. So I test both proposals, but unfortunately none of them work.
Maybe the solution could be skipping the routes, which contains empty arguments to prevent the InvalidParameterException? In the example above we use the config to prevent side effects.
Updated by Stefan Berger over 4 years ago
After some testing we found than also other Enhancers are affected. So we removed the config shown above and remove all empty parameters that are passed in the PageRouter::generateUri().
This will now fix the problems concerning the issue for all Enhancers without config.
class PageRouter extends PageRouterCore { public function generateUri($route, array $parameters = [], string $fragment = '', string $type = ''): UriInterface { $removeEmptyParameter = function ($array) use (&$removeEmptyParameter) { $callback = function($value) { return !is_null($value) && $value !== ''; }; foreach ($array as &$value) { if (is_array($value)) { $value = $removeEmptyParameter($value, $callback); } } return array_filter($array, $callback); }; return parent::generateUri($route, $removeEmptyParameter($parameters), $fragment, $type); } }
Updated by Oliver Hader about 2 years ago
- Assignee set to Oliver Hader
- Sprint Focus set to On Location Sprint
Updated by Oliver Hader about 2 years ago
I've tested this again with this complete example
routeEnhancers: PageTypeSuffix: type: PageType default: '/' index: '' map: '/': 0 Example: type: Extbase extension: Example plugin: Pi1 defaultController: 'Category::list' routes: - routePath: '/category' _controller: 'Category::list' - routePath: '/category/{category_slug}' _controller: 'Category::list' _arguments: category_slug: category # important, no `defaults` section here for `category_slug` # there are two explicits routes now
generateUri('?id=1&tx_example_pi1[category]=1')
→ /page/category/name-of-category-1/
generateUri('?id=1&tx_example_pi1[controller]=Category')
→ /page/category/
(tx_example_pi1[controller]
is required to give a hint for that particular enhancer configuration)
- basically this is the substitute for
generateUri('?id=1&tx_example_pi1[category]=')
, which still fails - and this is expected since there must be a value, e.g.&tx_example_pi1[category]=0
would work) - removing all blank (
''
) parameters per default might be breaking, since some other mapper, enhancer, ... could rely/handler exactly those cases already
Thus, I currently don't see the necessity to remove blank parameters. In case that would be implemented, I should be very specific for particular parameters (not for all).
Updated by Oliver Hader about 2 years ago
- Status changed from Needs Feedback to Closed
Updated by Oliver Hader about 2 years ago
Forgot to explain, why it fails. The PageType
decorator adds a slash /
to the end of each route path, which then looks like this:
/category/{tx_example_pi1_0}/
Since there must be a slash at the end, the parameter {tx_example_pi1_0}
cannot be optional anymore. The only work-around would be to declare requirements.category_slug: '.*'
. As a result, the generated URI would then be /category//
(having two slashes at the end).