From 3cd824cb0bb4036fe63162724e50f445e42a3c58 Mon Sep 17 00:00:00 2001 From: Xiao Hu Tai Date: Tue, 1 Oct 2019 17:11:43 +0200 Subject: [PATCH] Split routes automatically when exceeding regex limits --- config/config.yml.dist | 3 +- .../HierarchicalRoutesController.php | 34 +++++++++++++++---- src/Controller/Requirement.php | 17 ++++++++++ src/Routing/HierarchicalUrlGenerator.php | 20 +++++++++++ 4 files changed, 66 insertions(+), 8 deletions(-) diff --git a/config/config.yml.dist b/config/config.yml.dist index e693935..c653cb8 100644 --- a/config/config.yml.dist +++ b/config/config.yml.dist @@ -49,9 +49,10 @@ rules: # When using Bolt Translate, the Bolt Translate routing should # take over, so set this to `false`. Bolt Translate integration # is not working. -# +# bypass-url-generator: Bypasses the URL generator. This is generally kept `false`. settings: overwrite-duplicates : true override-slugs : false enable-routing : true + bypass-url-generator : false diff --git a/src/Controller/HierarchicalRoutesController.php b/src/Controller/HierarchicalRoutesController.php index 6f2b6d8..284004e 100644 --- a/src/Controller/HierarchicalRoutesController.php +++ b/src/Controller/HierarchicalRoutesController.php @@ -34,13 +34,33 @@ public function connect(Application $app) $requirement = $app['hierarchicalroutes.controller.requirement']; - $ctr - ->match("/{slug}", [$this, 'recordExactMatch']) - ->assert('slug', $requirement->anyRecordRouteConstraint()) - ->before('controller.frontend:before') - ->after('controller.frontend:after') - ->bind('hierarchicalroutes.record.exact') - ; + // A site with many pages or deeply nested pages (usually a combination of both) + // results in an error. In this case split into multiple routes. The limit is set + // around 32767 and requires a re-compile of PHP in order to change this limit. + // Downside of this method is to that URL generation also becomes more complicated. + $anyRecordRouteConstraint = $requirement->anyRecordRouteConstraint(); + if (strlen($anyRecordRouteConstraint) > 30000) { + $index = 0; + $groups = $requirement->anyRecordRouteConstraintSplitted(); + foreach ($groups as $group) { + $ctr + ->match("/{slug}", [$this, 'recordExactMatch']) + ->assert('slug', $group) + ->before('controller.frontend:before') + ->after('controller.frontend:after') + ->bind('hierarchicalroutes.record.exact_' . $index) + ; + $index++; + } + } else { + $ctr + ->match("/{slug}", [$this, 'recordExactMatch']) + ->assert('slug', $anyRecordRouteConstraint) + ->before('controller.frontend:before') + ->after('controller.frontend:after') + ->bind('hierarchicalroutes.record.exact') + ; + } $ctr ->match("/{slug}", [$this, 'listingExactMatch']) diff --git a/src/Controller/Requirement.php b/src/Controller/Requirement.php index 568795d..f9a521e 100644 --- a/src/Controller/Requirement.php +++ b/src/Controller/Requirement.php @@ -16,6 +16,8 @@ class Requirement private $listingRoutes = []; private $potentialParents = []; + private $chunkSize = 100; + /** * @param HierarchicalRoutesService $service */ @@ -30,6 +32,21 @@ public function __construct(HierarchicalRoutesService $service) $this->potentialParents = $this->service->getPotentialParents(); } + /** + * @return array + */ + public function anyRecordRouteConstraintSplitted() + { + $result = []; + $chunks = array_chunk($this->recordRoutes, $this->chunkSize); + + foreach ($chunks as $chunk) { + $result[] = $this->createConstraints($chunk); + } + + return $result; + } + /** * @return string */ diff --git a/src/Routing/HierarchicalUrlGenerator.php b/src/Routing/HierarchicalUrlGenerator.php index 0ba9b98..f7136f3 100644 --- a/src/Routing/HierarchicalUrlGenerator.php +++ b/src/Routing/HierarchicalUrlGenerator.php @@ -40,6 +40,7 @@ public function generate($name, $parameters = [], $referenceType = UrlGeneratorI { $config = $this->app['hierarchicalroutes.config']; $enableRouting = $config->get('settings/enable-routing', true); + $bypassUrlGenerator = $config->get('settings/bypass-url-generator', false); if ($enableRouting && $name == 'contentlink') { $service = $this->app['hierarchicalroutes.service']; @@ -55,10 +56,29 @@ public function generate($name, $parameters = [], $referenceType = UrlGeneratorI $recordRoutes = $service->getRecordRoutes(); if (isset($recordRoutes["$contenttypeslug/$slug"])) { + if ($bypassUrlGenerator) { + return '/' . $recordRoutes["$contenttypeslug/$slug"]; + } + $name = 'hierarchicalroutes.record.exact'; $parameters = [ 'slug' => $recordRoutes["$contenttypeslug/$slug"], ]; + + $requirement = $this->app['hierarchicalroutes.controller.requirement']; + $anyRecordRouteConstraint = $requirement->anyRecordRouteConstraint(); + if (strlen($anyRecordRouteConstraint) > 30000) { + $groups = $requirement->anyRecordRouteConstraintSplitted(); + $index = 0; + foreach ($groups as $group) { + $matches = preg_match("($group)", $parameters['slug']); + if ($matches === 1) { + return $this->wrapped->generate($name . '_' . $index, $parameters, $referenceType); + } + $index++; + } + } + return $this->wrapped->generate($name, $parameters, $referenceType); }