Created
June 6, 2023 21:28
-
-
Save thelebster/6d06e11b4f43f53464f235db18b6850a to your computer and use it in GitHub Desktop.
Revisions
-
thelebster created this gist
Jun 6, 2023 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,95 @@ The goal is to provide a dynamic (wildcard) route that should match on all nested routes that starts from some string. The main issue is that [Drupal routing system](https://www.drupal.org/docs/drupal-apis/routing-system/routing-system-overview), does not provide a clean way to describe a wildcard routes that should match some kind of pattern, like `/UserGuide`, `/UserGuide/Development_Notes` or `/UserGuide/Release_Notes/3.0.x` etc. Initial idea is to use dynamic routes, that will work in case when routes are known or could be generated by some pattern, like `/UserGuide/node/1`, `/UserGuide/node/2` etc. Otherwise this is not possible, like when the route could consist from the multiple undefined parts. As one possible solution, I decided to try the [inbound path processor](https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21PathProcessor%21InboundPathProcessorInterface.php/interface/InboundPathProcessorInterface/10) to catch destination path to redirect to the page controller, and pass an original path as a query parameter. File **example/example.routing.yml**: ``` example.user_guide: path: '/UserGuide' defaults: _controller: '\Drupal\example\Controller\ExamplePageController::view' _title: 'User Guide' requirements: _access: 'TRUE' ``` File **example/example.services.yml**: ``` services: example.path_processor: class: Drupal\example\PathProcessor\ExamplePathProcessor tags: - { name: path_processor_inbound, priority: 1000 } ``` File **example/src/PathProcessor/ExamplePathProcessor.php**: ``` <?php namespace Drupal\example\ExamplePathProcessor; use Drupal\Core\PathProcessor\InboundPathProcessorInterface; use Symfony\Component\HttpFoundation\Request; // Before PHP 8, use a polyfill. // @see https://www.php.net/manual/en/function.str-starts-with.php if (!function_exists('str_starts_with')) { function str_starts_with($haystack, $needle) { return (string) $needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0; } } class ExamplePathProcessor implements InboundPathProcessorInterface { /** * {@inheritdoc} */ public function processInbound($path, Request $request) { if (!str_starts_with($path, '/UserGuide')) return $path; // Remove leading slash. $original_path = ltrim(str_replace('/UserGuide', '', $path), '/'); $request->query->set('original_path', $original_path); return '/UserGuide'; } } ``` File **example/src/Controller/ExamplePageController.php**: ``` <?php namespace Drupal\example\Controller; use Drupal\Core\Controller\ControllerBase; class ExamplePageController extends ControllerBase { public function view() { $request_query = \Drupal::request()->query->all(); // Get an original path. $original_path = $request_query['original_path']; // Do anything else... // For example, try to fetch page content from some external API etc. $page_content = self::getPageContent($original_path); if (empty($page_content)) { // Return 404 not found if page does not exist. throw new \Symfony\Component\HttpKernel\Exception\NotFoundHttpException(); } // Return a renderable array with a page content. return $build; } } ```