facets-8.x-1.x-dev/src/Utility/FacetsUrlGenerator.php

src/Utility/FacetsUrlGenerator.php
<?php

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.
 */
class FacetsUrlGenerator {

  /**
   * The url processor plugin manager.
   *
   * @var \Drupal\facets\UrlProcessor\UrlProcessorPluginManager
   */
  protected $urlProcessorPluginManager;

  /**
   * The entity storage for facets.
   *
   * @var \Drupal\Core\Entity\EntityStorageInterface
   */
  protected $facetStorage;

  /**
   * Constructs a new instance of the FacetsUrlGenerator.
   *
   * @param \Drupal\facets\UrlProcessor\UrlProcessorPluginManager $urlProcessorPluginManager
   *   The url processor plugin manager.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
   *   The entity type manager.
   */
  public function __construct(UrlProcessorPluginManager $urlProcessorPluginManager, EntityTypeManagerInterface $entityTypeManager) {
    $this->urlProcessorPluginManager = $urlProcessorPluginManager;
    $this->facetStorage = $entityTypeManager->getStorage('facets_facet');
  }

  /**
   * Returns an URL object for a facet path.
   *
   * Example implementations:
   * @code
   * // Example to generate URL for 1 facet with 1 value.
   * \Drupal::service('facets.utility.url_generator')->getUrl(['tags' => [7]]);
   * // Example with multiple active filters.
   * $active_filters = ['tags' => [5, 7], 'color' => ['blue']];
   * \Drupal::service('facets.utility.url_generator')->getUrl($active_filters);
   * @endcode
   *
   * @param array $active_filters
   *   An array containing the active filters with key being the facet id and
   *   value being an array of raw values.
   * @param bool $keep_active
   *   TRUE if the currently active facets should be included to the URL or
   *   FALSE if they should be discarded. Defaults to TRUE.
   *
   * @return \Drupal\Core\Url|null
   *   A Url object for the given facet/value combination or null if no Result
   *   was returned by the UrlProcessor.
   *
   * @throws \InvalidArgumentException
   */
  public function getUrl(array $active_filters, $keep_active = TRUE): ?Url {
    // We use the first defined facet to load the url processor. As all facets
    // should be from the same facet source, this is fine.
    // This is because we don't support generating a url over multiple facet
    // sources.
    if (empty($active_filters)) {
      throw new \InvalidArgumentException("The active filters passed in are invalid. They should look like: ['facet_id' => ['value1', 'value2']]");
    }

    $facet_id = key($active_filters);
    if (!is_array($active_filters[$facet_id])) {
      throw new \InvalidArgumentException("The active filters passed in are invalid. They should look like: [$facet_id => ['value1', 'value2']]");
    }

    $facet = $this->facetStorage->load($facet_id);
    if ($facet === NULL) {
      throw new \InvalidArgumentException("The Facet $facet_id could not be loaded.");
    }

    // We need one raw value to build a Result. If we have the raw value in the
    // already active filters, it will be removed in the final result. So
    // instead we copy the value into a variable and unset it from the list.
    $raw_value = $active_filters[$facet_id][0];
    unset($active_filters[$facet_id][0]);

    /** @var \Drupal\facets\UrlProcessor\UrlProcessorInterface $url_processor */
    $url_processor = $this
      ->urlProcessorPluginManager
      ->createInstance($facet->getFacetSourceConfig()
        ->getUrlProcessorName(), ['facet' => $facet]);

    if ($keep_active) {
      $active_filters = array_merge_recursive($active_filters, $url_processor->getActiveFilters());
    }
    $url_processor->setActiveFilters($active_filters);

    // Use the url processor to create a result and return that item's url.
    $results = [new Result($facet, $raw_value, '', 0)];
    $processed_results = $url_processor->buildUrls($facet, $results);
    $result = reset($processed_results);
    if ($result) {
      return $result->getUrl();
    }
    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. But every time you call this function
   * you'll get a fresh clone of the URL object that could be manipulated
   * individually.
   *
   * @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)) {
      // 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 clone $requestUrlsByPath[$request_uri];
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc