*/ class Candidates implements CandidatesInterface { /** * @var array */ protected $locales; /** * A limit to apply to the number of candidates generated. * * This is to prevent abusive requests with a lot of "/". The limit is per * batch, that is if a locale matches you could get as many as 2 * $limit * candidates if the URL has that many slashes. * * @var int */ protected $limit; /** * @param array $locales The locales to support. * @param int $limit A limit to apply to the candidates generated. */ public function __construct(array $locales = array(), $limit = 20) { $this->setLocales($locales); $this->limit = $limit; } /** * Set the locales to support by this strategy. * * @param array $locales The locales to support. */ public function setLocales(array $locales) { $this->locales = $locales; } /** * {@inheritdoc} * * Always returns true. */ public function isCandidate($name) { return true; } /** * {@inheritdoc} * * Does nothing. */ public function restrictQuery($queryBuilder) { } /** * {@inheritdoc} */ public function getCandidates(Request $request) { $url = $request->getPathInfo(); $candidates = $this->getCandidatesFor($url); $locale = $this->determineLocale($url); if ($locale) { $candidates = array_unique(array_merge($candidates, $this->getCandidatesFor(substr($url, strlen($locale) + 1)))); } return $candidates; } /** * Determine the locale of this URL. * * @param string $url The url to determine the locale from. * * @return string|bool The locale if $url starts with one of the allowed locales. */ protected function determineLocale($url) { if (!count($this->locales)) { return false; } $matches = array(); if (preg_match('#^/('.implode('|', $this->locales).')(/|$)#', $url, $matches)) { return $matches[1]; } return false; } /** * Handle a possible format extension and split the $url on "/". * * $prefix is prepended to every candidate generated. * * @param string $url The URL to split. * @param string $prefix A prefix to prepend to every pattern. * * @return array Paths that could represent routes that match $url and are * child of $prefix. */ protected function getCandidatesFor($url, $prefix = '') { $candidates = array(); if ('/' !== $url) { // handle format extension, like .html or .json if (preg_match('/(.+)\.[a-z]+$/i', $url, $matches)) { $candidates[] = $prefix.$url; $url = $matches[1]; } $part = $url; $count = 0; while (false !== ($pos = strrpos($part, '/'))) { if (++$count > $this->limit) { return $candidates; } $candidates[] = $prefix.$part; $part = substr($url, 0, $pos); } } $candidates[] = $prefix ?: '/'; return $candidates; } }