You are here

class ContentAwareGenerator in Zircon Profile 8

Same name and namespace in other branches
  1. 8.0 vendor/symfony-cmf/routing/ContentAwareGenerator.php \Symfony\Cmf\Component\Routing\ContentAwareGenerator

A generator that tries to generate routes from object, route names or content objects or names.

@author Philippo de Santis @author David Buchmann @author Uwe Jäger

Hierarchy

Expanded class hierarchy of ContentAwareGenerator

1 file declares its use of ContentAwareGenerator
ContentAwareGeneratorTest.php in vendor/symfony-cmf/routing/Tests/Routing/ContentAwareGeneratorTest.php

File

vendor/symfony-cmf/routing/ContentAwareGenerator.php, line 27

Namespace

Symfony\Cmf\Component\Routing
View source
class ContentAwareGenerator extends ProviderBasedGenerator {

  /**
   * The locale to use when neither the parameters nor the request context
   * indicate the locale to use.
   *
   * @var string
   */
  protected $defaultLocale = null;

  /**
   * The content repository used to find content by it's id
   * This can be used to specify a parameter content_id when generating urls
   *
   * This is optional and might not be initialized.
   *
   * @var  ContentRepositoryInterface
   */
  protected $contentRepository;

  /**
   * Set an optional content repository to find content by ids
   *
   * @param ContentRepositoryInterface $contentRepository
   */
  public function setContentRepository(ContentRepositoryInterface $contentRepository) {
    $this->contentRepository = $contentRepository;
  }

  /**
   * {@inheritDoc}
   *
   * @param string $name       ignored.
   * @param array  $parameters must either contain the field 'route' with a
   *                           RouteObjectInterface or the field 'content_id'
   *                           with the id of a document implementing
   *                           RouteReferrersReadInterface.
   *
   * @throws RouteNotFoundException If there is no such route in the database
   */
  public function generate($name, $parameters = array(), $absolute = false) {
    if ($name instanceof SymfonyRoute) {
      $route = $this
        ->getBestLocaleRoute($name, $parameters);
    }
    elseif (is_string($name) && $name) {
      $route = $this
        ->getRouteByName($name, $parameters);
    }
    else {
      $route = $this
        ->getRouteByContent($name, $parameters);
    }
    if (!$route instanceof SymfonyRoute) {
      $hint = is_object($route) ? get_class($route) : gettype($route);
      throw new RouteNotFoundException('Route of this document is not an instance of Symfony\\Component\\Routing\\Route but: ' . $hint);
    }
    $this
      ->unsetLocaleIfNotNeeded($route, $parameters);
    return parent::generate($route, $parameters, $absolute);
  }

  /**
   * Get the route by a string name
   *
   * @param string $route
   * @param array  $parameters
   *
   * @return SymfonyRoute
   *
   * @throws RouteNotFoundException if there is no route found for the provided name
   */
  protected function getRouteByName($name, array $parameters) {
    $route = $this->provider
      ->getRouteByName($name);
    if (empty($route)) {
      throw new RouteNotFoundException('No route found for name: ' . $name);
    }
    return $this
      ->getBestLocaleRoute($route, $parameters);
  }

  /**
   * Determine if there is a route with matching locale associated with the
   * given route via associated content.
   *
   * @param SymfonyRoute $route
   * @param array        $parameters
   *
   * @return SymfonyRoute either the passed route or an alternative with better locale
   */
  protected function getBestLocaleRoute(SymfonyRoute $route, $parameters) {
    if (!$route instanceof RouteObjectInterface) {

      // this route has no content, we can't get the alternatives
      return $route;
    }
    $locale = $this
      ->getLocale($parameters);
    if (!$this
      ->checkLocaleRequirement($route, $locale)) {
      $content = $route
        ->getContent();
      if ($content instanceof RouteReferrersReadInterface) {
        $routes = $content
          ->getRoutes();
        $contentRoute = $this
          ->getRouteByLocale($routes, $locale);
        if ($contentRoute) {
          return $contentRoute;
        }
      }
    }
    return $route;
  }

  /**
   * Get the route based on the $name that is an object implementing
   * RouteReferrersReadInterface or a content found in the content repository
   * with the content_id specified in parameters that is an instance of
   * RouteReferrersReadInterface.
   *
   * Called in generate when there is no route given in the parameters.
   *
   * If there is more than one route for the content, tries to find the
   * first one that matches the _locale (provided in $parameters or otherwise
   * defaulting to the request locale).
   *
   * If no route with matching locale is found, falls back to just return the
   * first route.
   *
   * @param mixed $name
   * @param array $parameters which should contain a content field containing
   *                          a RouteReferrersReadInterface object
   *
   * @return SymfonyRoute the route instance
   *
   * @throws RouteNotFoundException if no route can be determined
   */
  protected function getRouteByContent($name, &$parameters) {
    if ($name instanceof RouteReferrersReadInterface) {
      $content = $name;
    }
    elseif (isset($parameters['content_id']) && null !== $this->contentRepository) {
      $content = $this->contentRepository
        ->findById($parameters['content_id']);
      if (empty($content)) {
        throw new RouteNotFoundException('The content repository found nothing at id ' . $parameters['content_id']);
      }
      if (!$content instanceof RouteReferrersReadInterface) {
        throw new RouteNotFoundException('Content repository did not return a RouteReferrersReadInterface instance for id ' . $parameters['content_id']);
      }
    }
    else {
      $hint = is_object($name) ? get_class($name) : gettype($name);
      throw new RouteNotFoundException("The route name argument '{$hint}' is not RouteReferrersReadInterface instance and there is no 'content_id' parameter");
    }
    $routes = $content
      ->getRoutes();
    if (empty($routes)) {
      $hint = $this->contentRepository && $this->contentRepository
        ->getContentId($content) ? $this->contentRepository
        ->getContentId($content) : get_class($content);
      throw new RouteNotFoundException('Content document has no route: ' . $hint);
    }
    unset($parameters['content_id']);
    $route = $this
      ->getRouteByLocale($routes, $this
      ->getLocale($parameters));
    if ($route) {
      return $route;
    }

    // if none matched, randomly return the first one
    if ($routes instanceof Collection) {
      return $routes
        ->first();
    }
    return reset($routes);
  }

  /**
   * @param RouteCollection $routes
   * @param string          $locale
   *
   * @return bool|SymfonyRoute false if no route requirement matches the provided locale
   */
  protected function getRouteByLocale($routes, $locale) {
    foreach ($routes as $route) {
      if (!$route instanceof SymfonyRoute) {
        continue;
      }
      if ($this
        ->checkLocaleRequirement($route, $locale)) {
        return $route;
      }
    }
    return false;
  }

  /**
   * @param SymfonyRoute $route
   * @param string       $locale
   *
   * @return bool true if there is either no $locale, no _locale requirement
   *              on the route or if the requirement and the passed $locale
   *              match.
   */
  private function checkLocaleRequirement(SymfonyRoute $route, $locale) {
    return empty($locale) || !$route
      ->getRequirement('_locale') || preg_match('/' . $route
      ->getRequirement('_locale') . '/', $locale);
  }

  /**
   * Determine the locale to be used with this request
   *
   * @param array $parameters the parameters determined by the route
   *
   * @return string the locale following of the parameters or any other
   *                information the router has available. defaultLocale if no
   *                other locale can be determined.
   */
  protected function getLocale($parameters) {
    if (isset($parameters['_locale'])) {
      return $parameters['_locale'];
    }
    if ($this
      ->getContext()
      ->hasParameter('_locale')) {
      return $this
        ->getContext()
        ->getParameter('_locale');
    }
    return $this->defaultLocale;
  }

  /**
   * Overwrite the locale to be used by default if there is neither one in
   * the parameters when building the route nor a request available (i.e. CLI).
   *
   * @param string $locale
   */
  public function setDefaultLocale($locale) {
    $this->defaultLocale = $locale;
  }

  /**
   * We additionally support empty name and data in parameters and RouteAware content
   */
  public function supports($name) {
    return !$name || parent::supports($name) || $name instanceof RouteReferrersReadInterface;
  }

  /**
   * {@inheritDoc}
   */
  public function getRouteDebugMessage($name, array $parameters = array()) {
    if (empty($name) && isset($parameters['content_id'])) {
      return 'Content id ' . $parameters['content_id'];
    }
    if ($name instanceof RouteReferrersReadInterface) {
      return 'Route aware content ' . parent::getRouteDebugMessage($name, $parameters);
    }
    return parent::getRouteDebugMessage($name, $parameters);
  }

  /**
   * If the _locale parameter is allowed by the requirements of the route
   * and it is the default locale, remove it from the parameters so that we
   * do not get an unneeded ?_locale= query string.
   *
   * @param SymfonyRoute $route      The route being generated.
   * @param array        $parameters The parameters used, will be modified to
   *                                 remove the _locale field if needed.
   */
  protected function unsetLocaleIfNotNeeded(SymfonyRoute $route, array &$parameters) {
    $locale = $this
      ->getLocale($parameters);
    if (null !== $locale) {
      if (preg_match('/' . $route
        ->getRequirement('_locale') . '/', $locale) && $locale == $route
        ->getDefault('_locale')) {
        $compiledRoute = $route
          ->compile();
        if (!in_array('_locale', $compiledRoute
          ->getVariables())) {
          unset($parameters['_locale']);
        }
      }
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
ContentAwareGenerator::$contentRepository protected property The content repository used to find content by it's id This can be used to specify a parameter content_id when generating urls
ContentAwareGenerator::$defaultLocale protected property The locale to use when neither the parameters nor the request context indicate the locale to use.
ContentAwareGenerator::checkLocaleRequirement private function
ContentAwareGenerator::generate public function Overrides ProviderBasedGenerator::generate
ContentAwareGenerator::getBestLocaleRoute protected function Determine if there is a route with matching locale associated with the given route via associated content.
ContentAwareGenerator::getLocale protected function Determine the locale to be used with this request 1
ContentAwareGenerator::getRouteByContent protected function Get the route based on the $name that is an object implementing RouteReferrersReadInterface or a content found in the content repository with the content_id specified in parameters that is an instance of RouteReferrersReadInterface.
ContentAwareGenerator::getRouteByLocale protected function
ContentAwareGenerator::getRouteByName protected function Get the route by a string name
ContentAwareGenerator::getRouteDebugMessage public function Convert a route identifier (name, content object etc) into a string usable for logging and other debug/error messages Overrides ProviderBasedGenerator::getRouteDebugMessage
ContentAwareGenerator::setContentRepository public function Set an optional content repository to find content by ids
ContentAwareGenerator::setDefaultLocale public function Overwrite the locale to be used by default if there is neither one in the parameters when building the route nor a request available (i.e. CLI).
ContentAwareGenerator::supports public function We additionally support empty name and data in parameters and RouteAware content Overrides ProviderBasedGenerator::supports
ContentAwareGenerator::unsetLocaleIfNotNeeded protected function If the _locale parameter is allowed by the requirements of the route and it is the default locale, remove it from the parameters so that we do not get an unneeded ?_locale= query string.
ProviderBasedGenerator::$provider protected property The route provider for this generator.
ProviderBasedGenerator::__construct public function Overrides UrlGenerator::__construct
UrlGenerator::$context protected property
UrlGenerator::$decodedChars protected property This array defines the characters (besides alphanumeric ones) that will not be percent-encoded in the path segment of the generated URL.
UrlGenerator::$logger protected property
UrlGenerator::$routes protected property
UrlGenerator::$strictRequirements protected property
UrlGenerator::doGenerate protected function 2
UrlGenerator::getContext public function Gets the request context. Overrides RequestContextAwareInterface::getContext
UrlGenerator::getRelativePath public static function Returns the target path as relative reference from the base path.
UrlGenerator::isStrictRequirements public function Returns whether to throw an exception on incorrect parameters. Null means the requirements check is deactivated completely. Overrides ConfigurableRequirementsInterface::isStrictRequirements
UrlGenerator::setContext public function Sets the request context. Overrides RequestContextAwareInterface::setContext
UrlGenerator::setStrictRequirements public function Enables or disables the exception on incorrect parameters. Passing null will deactivate the requirements check completely. Overrides ConfigurableRequirementsInterface::setStrictRequirements
UrlGeneratorInterface::ABSOLUTE_PATH constant Generates an absolute path, e.g. "/dir/file".
UrlGeneratorInterface::ABSOLUTE_URL constant Generates an absolute URL, e.g. "http://example.com/dir/file".
UrlGeneratorInterface::NETWORK_PATH constant Generates a network path, e.g. "//example.com/dir/file". Such reference reuses the current scheme but specifies the host.
UrlGeneratorInterface::RELATIVE_PATH constant Generates a relative path based on the current request path, e.g. "../parent-file".