Loading facets.info.yml +1 −1 Original line number Diff line number Diff line name: 'Facets' type: module description: 'Faceted search interfaces that can be used on Search API searchers.' core_version_requirement: ^9.2 || ^10.0 core_version_requirement: ^9.3 || ^10.0 package: Search configure: entity.facets_facet.collection test_dependencies: Loading src/Plugin/facets/url_processor/QueryString.php +17 −38 Original line number Diff line number Diff line Loading @@ -5,16 +5,15 @@ namespace Drupal\facets\Plugin\facets\url_processor; use Drupal\Core\Cache\UnchangingCacheableDependencyTrait; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\EventSubscriber\MainContentViewSubscriber; use Drupal\Core\Url; use Drupal\facets\Event\ActiveFiltersParsed; use Drupal\facets\Event\QueryStringCreated; use Drupal\facets\Event\UrlCreated; use Drupal\facets\FacetInterface; use Drupal\facets\UrlProcessor\UrlProcessorPluginBase; use Drupal\facets\Utility\FacetsUrlGenerator; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Exception\ResourceNotFoundException; /** * Query string URL processor. Loading Loading @@ -43,12 +42,20 @@ class QueryString extends UrlProcessorPluginBase { */ protected $eventDispatcher; /** * The URL generator. * * @var \Drupal\facets\Utility\FacetsUrlGenerator */ protected $urlGenerator; /** * {@inheritdoc} */ public function __construct(array $configuration, $plugin_id, $plugin_definition, Request $request, EntityTypeManagerInterface $entity_type_manager, EventDispatcherInterface $eventDispatcher) { public function __construct(array $configuration, $plugin_id, $plugin_definition, Request $request, EntityTypeManagerInterface $entity_type_manager, EventDispatcherInterface $eventDispatcher, FacetsUrlGenerator $urlGenerator) { parent::__construct($configuration, $plugin_id, $plugin_definition, $request, $entity_type_manager); $this->eventDispatcher = $eventDispatcher; $this->urlGenerator = $urlGenerator; $this->initializeActiveFilters(); } Loading @@ -62,7 +69,8 @@ class QueryString extends UrlProcessorPluginBase { $plugin_definition, $container->get('request_stack')->getCurrentRequest(), $container->get('entity_type.manager'), $container->get('event_dispatcher') $container->get('event_dispatcher'), $container->get('facets.utility.url_generator') ); } Loading @@ -88,6 +96,8 @@ class QueryString extends UrlProcessorPluginBase { // Set the url alias from the facet object. $this->urlAlias = $facet->getUrlAlias(); // In case of a view page display, the facet source has a path, If the // source is a block, the path is null. $facet_source_path = $facet->getFacetSource()->getPath(); $request = $this->getRequestByFacetSourcePath($facet_source_path); $requestUrl = $this->getUrlForRequest($facet_source_path, $request); Loading Loading @@ -274,9 +284,8 @@ class QueryString extends UrlProcessorPluginBase { /** * Gets the URL object for a request. * * This method statically caches the URL object for a request based on the * facet source path. This reduces subsequent calls to the processor from * having to regenerate the URL object. * This method delegates to the URL generator service. But we keep it for * backward compatibility for custom implementations that extend this class. * * @param string $facet_source_path * The facet source path. Loading @@ -287,37 +296,7 @@ class QueryString extends UrlProcessorPluginBase { * The URL. */ protected function getUrlForRequest($facet_source_path, Request $request) { /** @var \Drupal\Core\Url[] $requestUrlsByPath */ $requestUrlsByPath = &drupal_static(__CLASS__ . __FUNCTION__, []); if (array_key_exists($facet_source_path, $requestUrlsByPath)) { return $requestUrlsByPath[$facet_source_path]; } // Try to grab any route params from the original request. // In case of request path not having a matching route, Url generator will // fail with. try { $requestUrl = Url::createFromRequest($request); } catch (ResourceNotFoundException $e) { // Bypass exception if no path available. // Should be unreachable in default FacetSource implementations, // but you never know. if (!$facet_source_path) { throw $e; } $requestUrl = Url::fromUserInput($facet_source_path, [ 'query' => [ '_format' => $this->request->get('_format'), ], ]); } $requestUrl->setOption('attributes', ['rel' => 'nofollow']); $requestUrlsByPath[$facet_source_path] = $requestUrl; return $requestUrl; return $this->urlGenerator->getUrlForRequest($request, $facet_source_path); } /** Loading src/Plugin/facets/widget/LinksWidget.php +4 −4 Original line number Diff line number Diff line Loading @@ -67,14 +67,14 @@ class LinksWidget extends WidgetPluginBase { unset($active_filters[$facet->id()]); // Only if there are still active filters, use url generator. $urlGenerator = \Drupal::service('facets.utility.url_generator'); if ($active_filters) { $url = \Drupal::service('facets.utility.url_generator') ->getUrl($active_filters, FALSE); $url = $urlGenerator->getUrl($active_filters, FALSE); } else { $request = \Drupal::request(); $url = Url::createFromRequest($request); $facet_source = $facet->getFacetSource(); $url = $urlGenerator->getUrlForRequest($request, $facet_source ? $facet_source->getPath() : NULL); $params = $request->query->all(); unset($params[$url_processor->getFilterKey()]); if (\array_key_exists('page', $params)) { Loading src/UrlProcessor/UrlProcessorPluginBase.php +1 −3 Original line number Diff line number Diff line Loading @@ -127,9 +127,7 @@ abstract class UrlProcessorPluginBase extends ProcessorPluginBase implements Url $configuration, $plugin_id, $plugin_definition, // Support 9.3+. // @todo remove switch after 9.3 or greater is required. version_compare(\Drupal::VERSION, '9.3', '>=') ? $request_stack->getMainRequest() : $request_stack->getMasterRequest(), $request_stack->getMainRequest(), $container->get('entity_type.manager') ); } Loading src/Utility/FacetsUrlGenerator.php +68 −0 Original line number Diff line number Diff line Loading @@ -3,8 +3,11 @@ namespace Drupal\facets\Utility; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Url; use Drupal\facets\Result\Result; use Drupal\facets\UrlProcessor\UrlProcessorPluginManager; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Exception\ResourceNotFoundException; /** * Facets Url Generator service. Loading Loading @@ -109,4 +112,69 @@ class FacetsUrlGenerator { return NULL; } /** * Gets the URL object for a request. * * This method statically caches the URL object for a request based on the * facet source path. This reduces subsequent calls to the processor from * having to regenerate the URL object. * * @param \Symfony\Component\HttpFoundation\Request $request * The request. * @param string $facet_source_path * The facet source path. * * @return \Drupal\Core\Url * The URL. */ public function getUrlForRequest(Request $request, $facet_source_path = NULL): Url { /** @var \Drupal\Core\Url[] $requestUrlsByPath */ $requestUrlsByPath = &drupal_static(__CLASS__ . __FUNCTION__, []); $request_uri = $request->getRequestUri(); if (array_key_exists($request_uri, $requestUrlsByPath)) { return $requestUrlsByPath[$request_uri]; } // Try to grab any route params from the original request. // In case of request path not having a matching route, Url generator will // fail with. try { $requestUrl = Url::createFromRequest($request); } catch (ResourceNotFoundException $e) { // Bypass exception if no path available. // Should be unreachable in default FacetSource implementations, // but you never know. if ($facet_source_path) { $requestUrl = Url::fromUserInput($facet_source_path, [ 'query' => [ '_format' => \Drupal::request()->get('_format'), ], ]); } else { if ('system.404' === $request->attributes->get('_route')) { // It seems that a facet that is configured to be rendered without its // facet source is currently rendered on a dedicated "page not found" // page. If the facet source has a valid path we would not land here // but in the condition above. So the facet source must be view block // display or something similar. In this case we could assume that // such a facet takes care about its link target itself and doesn't // depend on the current path or the facet source path. Let's provide // the front page as valid fallback to let the facet do its job. $requestUrl = Url::fromRoute('<front>'); } else { throw $e; } } } $requestUrl->setOption('attributes', ['rel' => 'nofollow']); $requestUrlsByPath[$request_uri] = $requestUrl; return $requestUrl; } } Loading
facets.info.yml +1 −1 Original line number Diff line number Diff line name: 'Facets' type: module description: 'Faceted search interfaces that can be used on Search API searchers.' core_version_requirement: ^9.2 || ^10.0 core_version_requirement: ^9.3 || ^10.0 package: Search configure: entity.facets_facet.collection test_dependencies: Loading
src/Plugin/facets/url_processor/QueryString.php +17 −38 Original line number Diff line number Diff line Loading @@ -5,16 +5,15 @@ namespace Drupal\facets\Plugin\facets\url_processor; use Drupal\Core\Cache\UnchangingCacheableDependencyTrait; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\EventSubscriber\MainContentViewSubscriber; use Drupal\Core\Url; use Drupal\facets\Event\ActiveFiltersParsed; use Drupal\facets\Event\QueryStringCreated; use Drupal\facets\Event\UrlCreated; use Drupal\facets\FacetInterface; use Drupal\facets\UrlProcessor\UrlProcessorPluginBase; use Drupal\facets\Utility\FacetsUrlGenerator; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Exception\ResourceNotFoundException; /** * Query string URL processor. Loading Loading @@ -43,12 +42,20 @@ class QueryString extends UrlProcessorPluginBase { */ protected $eventDispatcher; /** * The URL generator. * * @var \Drupal\facets\Utility\FacetsUrlGenerator */ protected $urlGenerator; /** * {@inheritdoc} */ public function __construct(array $configuration, $plugin_id, $plugin_definition, Request $request, EntityTypeManagerInterface $entity_type_manager, EventDispatcherInterface $eventDispatcher) { public function __construct(array $configuration, $plugin_id, $plugin_definition, Request $request, EntityTypeManagerInterface $entity_type_manager, EventDispatcherInterface $eventDispatcher, FacetsUrlGenerator $urlGenerator) { parent::__construct($configuration, $plugin_id, $plugin_definition, $request, $entity_type_manager); $this->eventDispatcher = $eventDispatcher; $this->urlGenerator = $urlGenerator; $this->initializeActiveFilters(); } Loading @@ -62,7 +69,8 @@ class QueryString extends UrlProcessorPluginBase { $plugin_definition, $container->get('request_stack')->getCurrentRequest(), $container->get('entity_type.manager'), $container->get('event_dispatcher') $container->get('event_dispatcher'), $container->get('facets.utility.url_generator') ); } Loading @@ -88,6 +96,8 @@ class QueryString extends UrlProcessorPluginBase { // Set the url alias from the facet object. $this->urlAlias = $facet->getUrlAlias(); // In case of a view page display, the facet source has a path, If the // source is a block, the path is null. $facet_source_path = $facet->getFacetSource()->getPath(); $request = $this->getRequestByFacetSourcePath($facet_source_path); $requestUrl = $this->getUrlForRequest($facet_source_path, $request); Loading Loading @@ -274,9 +284,8 @@ class QueryString extends UrlProcessorPluginBase { /** * Gets the URL object for a request. * * This method statically caches the URL object for a request based on the * facet source path. This reduces subsequent calls to the processor from * having to regenerate the URL object. * This method delegates to the URL generator service. But we keep it for * backward compatibility for custom implementations that extend this class. * * @param string $facet_source_path * The facet source path. Loading @@ -287,37 +296,7 @@ class QueryString extends UrlProcessorPluginBase { * The URL. */ protected function getUrlForRequest($facet_source_path, Request $request) { /** @var \Drupal\Core\Url[] $requestUrlsByPath */ $requestUrlsByPath = &drupal_static(__CLASS__ . __FUNCTION__, []); if (array_key_exists($facet_source_path, $requestUrlsByPath)) { return $requestUrlsByPath[$facet_source_path]; } // Try to grab any route params from the original request. // In case of request path not having a matching route, Url generator will // fail with. try { $requestUrl = Url::createFromRequest($request); } catch (ResourceNotFoundException $e) { // Bypass exception if no path available. // Should be unreachable in default FacetSource implementations, // but you never know. if (!$facet_source_path) { throw $e; } $requestUrl = Url::fromUserInput($facet_source_path, [ 'query' => [ '_format' => $this->request->get('_format'), ], ]); } $requestUrl->setOption('attributes', ['rel' => 'nofollow']); $requestUrlsByPath[$facet_source_path] = $requestUrl; return $requestUrl; return $this->urlGenerator->getUrlForRequest($request, $facet_source_path); } /** Loading
src/Plugin/facets/widget/LinksWidget.php +4 −4 Original line number Diff line number Diff line Loading @@ -67,14 +67,14 @@ class LinksWidget extends WidgetPluginBase { unset($active_filters[$facet->id()]); // Only if there are still active filters, use url generator. $urlGenerator = \Drupal::service('facets.utility.url_generator'); if ($active_filters) { $url = \Drupal::service('facets.utility.url_generator') ->getUrl($active_filters, FALSE); $url = $urlGenerator->getUrl($active_filters, FALSE); } else { $request = \Drupal::request(); $url = Url::createFromRequest($request); $facet_source = $facet->getFacetSource(); $url = $urlGenerator->getUrlForRequest($request, $facet_source ? $facet_source->getPath() : NULL); $params = $request->query->all(); unset($params[$url_processor->getFilterKey()]); if (\array_key_exists('page', $params)) { Loading
src/UrlProcessor/UrlProcessorPluginBase.php +1 −3 Original line number Diff line number Diff line Loading @@ -127,9 +127,7 @@ abstract class UrlProcessorPluginBase extends ProcessorPluginBase implements Url $configuration, $plugin_id, $plugin_definition, // Support 9.3+. // @todo remove switch after 9.3 or greater is required. version_compare(\Drupal::VERSION, '9.3', '>=') ? $request_stack->getMainRequest() : $request_stack->getMasterRequest(), $request_stack->getMainRequest(), $container->get('entity_type.manager') ); } Loading
src/Utility/FacetsUrlGenerator.php +68 −0 Original line number Diff line number Diff line Loading @@ -3,8 +3,11 @@ namespace Drupal\facets\Utility; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Url; use Drupal\facets\Result\Result; use Drupal\facets\UrlProcessor\UrlProcessorPluginManager; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Exception\ResourceNotFoundException; /** * Facets Url Generator service. Loading Loading @@ -109,4 +112,69 @@ class FacetsUrlGenerator { return NULL; } /** * Gets the URL object for a request. * * This method statically caches the URL object for a request based on the * facet source path. This reduces subsequent calls to the processor from * having to regenerate the URL object. * * @param \Symfony\Component\HttpFoundation\Request $request * The request. * @param string $facet_source_path * The facet source path. * * @return \Drupal\Core\Url * The URL. */ public function getUrlForRequest(Request $request, $facet_source_path = NULL): Url { /** @var \Drupal\Core\Url[] $requestUrlsByPath */ $requestUrlsByPath = &drupal_static(__CLASS__ . __FUNCTION__, []); $request_uri = $request->getRequestUri(); if (array_key_exists($request_uri, $requestUrlsByPath)) { return $requestUrlsByPath[$request_uri]; } // Try to grab any route params from the original request. // In case of request path not having a matching route, Url generator will // fail with. try { $requestUrl = Url::createFromRequest($request); } catch (ResourceNotFoundException $e) { // Bypass exception if no path available. // Should be unreachable in default FacetSource implementations, // but you never know. if ($facet_source_path) { $requestUrl = Url::fromUserInput($facet_source_path, [ 'query' => [ '_format' => \Drupal::request()->get('_format'), ], ]); } else { if ('system.404' === $request->attributes->get('_route')) { // It seems that a facet that is configured to be rendered without its // facet source is currently rendered on a dedicated "page not found" // page. If the facet source has a valid path we would not land here // but in the condition above. So the facet source must be view block // display or something similar. In this case we could assume that // such a facet takes care about its link target itself and doesn't // depend on the current path or the facet source path. Let's provide // the front page as valid fallback to let the facet do its job. $requestUrl = Url::fromRoute('<front>'); } else { throw $e; } } } $requestUrl->setOption('attributes', ['rel' => 'nofollow']); $requestUrlsByPath[$request_uri] = $requestUrl; return $requestUrl; } }