vendor/symfony/routing/Route.php line 20

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\Routing;
  11. /**
  12.  * A Route describes a route and its parameters.
  13.  *
  14.  * @author Fabien Potencier <fabien@symfony.com>
  15.  * @author Tobias Schultze <http://tobion.de>
  16.  */
  17. class Route implements \Serializable
  18. {
  19.     private $path '/';
  20.     private $host '';
  21.     private $schemes = [];
  22.     private $methods = [];
  23.     private $defaults = [];
  24.     private $requirements = [];
  25.     private $options = [];
  26.     private $condition '';
  27.     /**
  28.      * @var CompiledRoute|null
  29.      */
  30.     private $compiled;
  31.     /**
  32.      * Constructor.
  33.      *
  34.      * Available options:
  35.      *
  36.      *  * compiler_class: A class name able to compile this route instance (RouteCompiler by default)
  37.      *  * utf8:           Whether UTF-8 matching is enforced ot not
  38.      *
  39.      * @param string          $path         The path pattern to match
  40.      * @param array           $defaults     An array of default parameter values
  41.      * @param array           $requirements An array of requirements for parameters (regexes)
  42.      * @param array           $options      An array of options
  43.      * @param string|null     $host         The host pattern to match
  44.      * @param string|string[] $schemes      A required URI scheme or an array of restricted schemes
  45.      * @param string|string[] $methods      A required HTTP method or an array of restricted methods
  46.      * @param string|null     $condition    A condition that should evaluate to true for the route to match
  47.      */
  48.     public function __construct(string $path, array $defaults = [], array $requirements = [], array $options = [], ?string $host ''$schemes = [], $methods = [], ?string $condition '')
  49.     {
  50.         $this->setPath($path);
  51.         $this->addDefaults($defaults);
  52.         $this->addRequirements($requirements);
  53.         $this->setOptions($options);
  54.         $this->setHost($host);
  55.         $this->setSchemes($schemes);
  56.         $this->setMethods($methods);
  57.         $this->setCondition($condition);
  58.     }
  59.     public function __serialize(): array
  60.     {
  61.         return [
  62.             'path' => $this->path,
  63.             'host' => $this->host,
  64.             'defaults' => $this->defaults,
  65.             'requirements' => $this->requirements,
  66.             'options' => $this->options,
  67.             'schemes' => $this->schemes,
  68.             'methods' => $this->methods,
  69.             'condition' => $this->condition,
  70.             'compiled' => $this->compiled,
  71.         ];
  72.     }
  73.     /**
  74.      * @return string
  75.      *
  76.      * @internal since Symfony 4.3
  77.      * @final since Symfony 4.3
  78.      */
  79.     public function serialize()
  80.     {
  81.         return serialize($this->__serialize());
  82.     }
  83.     public function __unserialize(array $data): void
  84.     {
  85.         $this->path $data['path'];
  86.         $this->host $data['host'];
  87.         $this->defaults $data['defaults'];
  88.         $this->requirements $data['requirements'];
  89.         $this->options $data['options'];
  90.         $this->schemes $data['schemes'];
  91.         $this->methods $data['methods'];
  92.         if (isset($data['condition'])) {
  93.             $this->condition $data['condition'];
  94.         }
  95.         if (isset($data['compiled'])) {
  96.             $this->compiled $data['compiled'];
  97.         }
  98.     }
  99.     /**
  100.      * @internal since Symfony 4.3
  101.      * @final since Symfony 4.3
  102.      */
  103.     public function unserialize($serialized)
  104.     {
  105.         $this->__unserialize(unserialize($serialized));
  106.     }
  107.     /**
  108.      * @return string The path pattern
  109.      */
  110.     public function getPath()
  111.     {
  112.         return $this->path;
  113.     }
  114.     /**
  115.      * Sets the pattern for the path.
  116.      *
  117.      * @param string $pattern The path pattern
  118.      *
  119.      * @return $this
  120.      */
  121.     public function setPath($pattern)
  122.     {
  123.         if (false !== strpbrk($pattern'?<')) {
  124.             $pattern preg_replace_callback('#\{(!?)(\w++)(<.*?>)?(\?[^\}]*+)?\}#', function ($m) {
  125.                 if (isset($m[4][0])) {
  126.                     $this->setDefault($m[2], '?' !== $m[4] ? substr($m[4], 1) : null);
  127.                 }
  128.                 if (isset($m[3][0])) {
  129.                     $this->setRequirement($m[2], substr($m[3], 1, -1));
  130.                 }
  131.                 return '{'.$m[1].$m[2].'}';
  132.             }, $pattern);
  133.         }
  134.         // A pattern must start with a slash and must not have multiple slashes at the beginning because the
  135.         // generated path for this route would be confused with a network path, e.g. '//domain.com/path'.
  136.         $this->path '/'.ltrim(trim($pattern), '/');
  137.         $this->compiled null;
  138.         return $this;
  139.     }
  140.     /**
  141.      * @return string The host pattern
  142.      */
  143.     public function getHost()
  144.     {
  145.         return $this->host;
  146.     }
  147.     /**
  148.      * Sets the pattern for the host.
  149.      *
  150.      * @param string $pattern The host pattern
  151.      *
  152.      * @return $this
  153.      */
  154.     public function setHost($pattern)
  155.     {
  156.         $this->host = (string) $pattern;
  157.         $this->compiled null;
  158.         return $this;
  159.     }
  160.     /**
  161.      * Returns the lowercased schemes this route is restricted to.
  162.      * So an empty array means that any scheme is allowed.
  163.      *
  164.      * @return string[] The schemes
  165.      */
  166.     public function getSchemes()
  167.     {
  168.         return $this->schemes;
  169.     }
  170.     /**
  171.      * Sets the schemes (e.g. 'https') this route is restricted to.
  172.      * So an empty array means that any scheme is allowed.
  173.      *
  174.      * @param string|string[] $schemes The scheme or an array of schemes
  175.      *
  176.      * @return $this
  177.      */
  178.     public function setSchemes($schemes)
  179.     {
  180.         $this->schemes array_map('strtolower', (array) $schemes);
  181.         $this->compiled null;
  182.         return $this;
  183.     }
  184.     /**
  185.      * Checks if a scheme requirement has been set.
  186.      *
  187.      * @param string $scheme
  188.      *
  189.      * @return bool true if the scheme requirement exists, otherwise false
  190.      */
  191.     public function hasScheme($scheme)
  192.     {
  193.         return \in_array(strtolower($scheme), $this->schemestrue);
  194.     }
  195.     /**
  196.      * Returns the uppercased HTTP methods this route is restricted to.
  197.      * So an empty array means that any method is allowed.
  198.      *
  199.      * @return string[] The methods
  200.      */
  201.     public function getMethods()
  202.     {
  203.         return $this->methods;
  204.     }
  205.     /**
  206.      * Sets the HTTP methods (e.g. 'POST') this route is restricted to.
  207.      * So an empty array means that any method is allowed.
  208.      *
  209.      * @param string|string[] $methods The method or an array of methods
  210.      *
  211.      * @return $this
  212.      */
  213.     public function setMethods($methods)
  214.     {
  215.         $this->methods array_map('strtoupper', (array) $methods);
  216.         $this->compiled null;
  217.         return $this;
  218.     }
  219.     /**
  220.      * @return array The options
  221.      */
  222.     public function getOptions()
  223.     {
  224.         return $this->options;
  225.     }
  226.     /**
  227.      * @return $this
  228.      */
  229.     public function setOptions(array $options)
  230.     {
  231.         $this->options = [
  232.             'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler',
  233.         ];
  234.         return $this->addOptions($options);
  235.     }
  236.     /**
  237.      * @return $this
  238.      */
  239.     public function addOptions(array $options)
  240.     {
  241.         foreach ($options as $name => $option) {
  242.             $this->options[$name] = $option;
  243.         }
  244.         $this->compiled null;
  245.         return $this;
  246.     }
  247.     /**
  248.      * Sets an option value.
  249.      *
  250.      * @param string $name  An option name
  251.      * @param mixed  $value The option value
  252.      *
  253.      * @return $this
  254.      */
  255.     public function setOption($name$value)
  256.     {
  257.         $this->options[$name] = $value;
  258.         $this->compiled null;
  259.         return $this;
  260.     }
  261.     /**
  262.      * Get an option value.
  263.      *
  264.      * @param string $name An option name
  265.      *
  266.      * @return mixed The option value or null when not given
  267.      */
  268.     public function getOption($name)
  269.     {
  270.         return $this->options[$name] ?? null;
  271.     }
  272.     /**
  273.      * Checks if an option has been set.
  274.      *
  275.      * @param string $name An option name
  276.      *
  277.      * @return bool true if the option is set, false otherwise
  278.      */
  279.     public function hasOption($name)
  280.     {
  281.         return \array_key_exists($name$this->options);
  282.     }
  283.     /**
  284.      * @return array The defaults
  285.      */
  286.     public function getDefaults()
  287.     {
  288.         return $this->defaults;
  289.     }
  290.     /**
  291.      * @return $this
  292.      */
  293.     public function setDefaults(array $defaults)
  294.     {
  295.         $this->defaults = [];
  296.         return $this->addDefaults($defaults);
  297.     }
  298.     /**
  299.      * @return $this
  300.      */
  301.     public function addDefaults(array $defaults)
  302.     {
  303.         if (isset($defaults['_locale']) && $this->isLocalized()) {
  304.             unset($defaults['_locale']);
  305.         }
  306.         foreach ($defaults as $name => $default) {
  307.             $this->defaults[$name] = $default;
  308.         }
  309.         $this->compiled null;
  310.         return $this;
  311.     }
  312.     /**
  313.      * Gets a default value.
  314.      *
  315.      * @param string $name A variable name
  316.      *
  317.      * @return mixed The default value or null when not given
  318.      */
  319.     public function getDefault($name)
  320.     {
  321.         return $this->defaults[$name] ?? null;
  322.     }
  323.     /**
  324.      * Checks if a default value is set for the given variable.
  325.      *
  326.      * @param string $name A variable name
  327.      *
  328.      * @return bool true if the default value is set, false otherwise
  329.      */
  330.     public function hasDefault($name)
  331.     {
  332.         return \array_key_exists($name$this->defaults);
  333.     }
  334.     /**
  335.      * Sets a default value.
  336.      *
  337.      * @param string $name    A variable name
  338.      * @param mixed  $default The default value
  339.      *
  340.      * @return $this
  341.      */
  342.     public function setDefault($name$default)
  343.     {
  344.         if ('_locale' === $name && $this->isLocalized()) {
  345.             return $this;
  346.         }
  347.         $this->defaults[$name] = $default;
  348.         $this->compiled null;
  349.         return $this;
  350.     }
  351.     /**
  352.      * @return array The requirements
  353.      */
  354.     public function getRequirements()
  355.     {
  356.         return $this->requirements;
  357.     }
  358.     /**
  359.      * @return $this
  360.      */
  361.     public function setRequirements(array $requirements)
  362.     {
  363.         $this->requirements = [];
  364.         return $this->addRequirements($requirements);
  365.     }
  366.     /**
  367.      * @return $this
  368.      */
  369.     public function addRequirements(array $requirements)
  370.     {
  371.         if (isset($requirements['_locale']) && $this->isLocalized()) {
  372.             unset($requirements['_locale']);
  373.         }
  374.         foreach ($requirements as $key => $regex) {
  375.             $this->requirements[$key] = $this->sanitizeRequirement($key$regex);
  376.         }
  377.         $this->compiled null;
  378.         return $this;
  379.     }
  380.     /**
  381.      * Returns the requirement for the given key.
  382.      *
  383.      * @param string $key The key
  384.      *
  385.      * @return string|null The regex or null when not given
  386.      */
  387.     public function getRequirement($key)
  388.     {
  389.         return $this->requirements[$key] ?? null;
  390.     }
  391.     /**
  392.      * Checks if a requirement is set for the given key.
  393.      *
  394.      * @param string $key A variable name
  395.      *
  396.      * @return bool true if a requirement is specified, false otherwise
  397.      */
  398.     public function hasRequirement($key)
  399.     {
  400.         return \array_key_exists($key$this->requirements);
  401.     }
  402.     /**
  403.      * Sets a requirement for the given key.
  404.      *
  405.      * @param string $key   The key
  406.      * @param string $regex The regex
  407.      *
  408.      * @return $this
  409.      */
  410.     public function setRequirement($key$regex)
  411.     {
  412.         if ('_locale' === $key && $this->isLocalized()) {
  413.             return $this;
  414.         }
  415.         $this->requirements[$key] = $this->sanitizeRequirement($key$regex);
  416.         $this->compiled null;
  417.         return $this;
  418.     }
  419.     /**
  420.      * @return string The condition
  421.      */
  422.     public function getCondition()
  423.     {
  424.         return $this->condition;
  425.     }
  426.     /**
  427.      * Sets the condition.
  428.      *
  429.      * @param string $condition The condition
  430.      *
  431.      * @return $this
  432.      */
  433.     public function setCondition($condition)
  434.     {
  435.         $this->condition = (string) $condition;
  436.         $this->compiled null;
  437.         return $this;
  438.     }
  439.     /**
  440.      * Compiles the route.
  441.      *
  442.      * @return CompiledRoute A CompiledRoute instance
  443.      *
  444.      * @throws \LogicException If the Route cannot be compiled because the
  445.      *                         path or host pattern is invalid
  446.      *
  447.      * @see RouteCompiler which is responsible for the compilation process
  448.      */
  449.     public function compile()
  450.     {
  451.         if (null !== $this->compiled) {
  452.             return $this->compiled;
  453.         }
  454.         $class $this->getOption('compiler_class');
  455.         return $this->compiled $class::compile($this);
  456.     }
  457.     private function sanitizeRequirement(string $key$regex)
  458.     {
  459.         if (!\is_string($regex)) {
  460.             throw new \InvalidArgumentException(sprintf('Routing requirement for "%s" must be a string.'$key));
  461.         }
  462.         if ('' !== $regex && '^' === $regex[0]) {
  463.             $regex = (string) substr($regex1); // returns false for a single character
  464.         }
  465.         if (str_ends_with($regex'$')) {
  466.             $regex substr($regex0, -1);
  467.         }
  468.         if ('' === $regex) {
  469.             throw new \InvalidArgumentException(sprintf('Routing requirement for "%s" cannot be empty.'$key));
  470.         }
  471.         return $regex;
  472.     }
  473.     private function isLocalized(): bool
  474.     {
  475.         return isset($this->defaults['_locale']) && isset($this->defaults['_canonical_route']) && ($this->requirements['_locale'] ?? null) === preg_quote($this->defaults['_locale'], RouteCompiler::REGEX_DELIMITER);
  476.     }
  477. }