vendor/pimcore/pimcore/models/Staticroute.php line 552

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Commercial License (PCL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  *  @license    http://www.pimcore.org/license     GPLv3 and PCL
  13.  */
  14. namespace Pimcore\Model;
  15. use Pimcore\Event\FrontendEvents;
  16. use Pimcore\Model\Exception\NotFoundException;
  17. use Symfony\Component\EventDispatcher\GenericEvent;
  18. /**
  19.  * @method bool isWriteable()
  20.  * @method string getWriteTarget()
  21.  * @method Staticroute\Dao getDao()
  22.  * @method void save()
  23.  * @method void delete()
  24.  */
  25. final class Staticroute extends AbstractModel
  26. {
  27.     /**
  28.      * @var string
  29.      */
  30.     protected $id;
  31.     /**
  32.      * @var string
  33.      */
  34.     protected $name;
  35.     /**
  36.      * @var string
  37.      */
  38.     protected $pattern;
  39.     /**
  40.      * @var string
  41.      */
  42.     protected $reverse;
  43.     /**
  44.      * @var string
  45.      */
  46.     protected $controller;
  47.     /**
  48.      * @var string
  49.      */
  50.     protected $variables;
  51.     /**
  52.      * @var string
  53.      */
  54.     protected $defaults;
  55.     /**
  56.      * @var array
  57.      */
  58.     protected $siteId = [];
  59.     /**
  60.      * @var array
  61.      */
  62.     protected $methods;
  63.     /**
  64.      * @var int
  65.      */
  66.     protected $priority 1;
  67.     /**
  68.      * @var int|null
  69.      */
  70.     protected $creationDate;
  71.     /**
  72.      * @var int|null
  73.      */
  74.     protected $modificationDate;
  75.     /**
  76.      * Associative array filled on match() that holds matched path values
  77.      * for given variable names.
  78.      *
  79.      * @var array
  80.      */
  81.     protected $_values = [];
  82.     /**
  83.      * this is a small per request cache to know which route is which is, this info is used in self::getByName()
  84.      *
  85.      * @var array
  86.      */
  87.     protected static $nameIdMappingCache = [];
  88.     /**
  89.      * contains the static route which the current request matches (it he does), this is used in the view to get the current route
  90.      *
  91.      * @var Staticroute|null
  92.      */
  93.     protected static ?Staticroute $_currentRoute null;
  94.     /**
  95.      * @static
  96.      *
  97.      * @param Staticroute|null $route
  98.      */
  99.     public static function setCurrentRoute(?Staticroute $route)
  100.     {
  101.         self::$_currentRoute $route;
  102.     }
  103.     /**
  104.      * @static
  105.      *
  106.      * @return Staticroute|null
  107.      */
  108.     public static function getCurrentRoute(): ?Staticroute
  109.     {
  110.         return self::$_currentRoute;
  111.     }
  112.     /**
  113.      * Static helper to retrieve an instance of Staticroute by the given ID
  114.      *
  115.      * @param string $id
  116.      *
  117.      * @return self|null
  118.      */
  119.     public static function getById($id)
  120.     {
  121.         $cacheKey 'staticroute_' $id;
  122.         try {
  123.             $route \Pimcore\Cache\Runtime::get($cacheKey);
  124.             if (!$route) {
  125.                 throw new \Exception('Route in registry is null');
  126.             }
  127.         } catch (\Exception $e) {
  128.             try {
  129.                 $route = new self();
  130.                 $route->setId($id);
  131.                 $route->getDao()->getById();
  132.                 \Pimcore\Cache\Runtime::set($cacheKey$route);
  133.             } catch (NotFoundException $e) {
  134.                 return null;
  135.             }
  136.         }
  137.         return $route;
  138.     }
  139.     /**
  140.      * @param string $name
  141.      * @param int|null $siteId
  142.      *
  143.      * @return self|null
  144.      *
  145.      * @throws \Exception
  146.      */
  147.     public static function getByName($name$siteId null)
  148.     {
  149.         $cacheKey $name '~~~' $siteId;
  150.         // check if pimcore already knows the id for this $name, if yes just return it
  151.         if (array_key_exists($cacheKeyself::$nameIdMappingCache)) {
  152.             return self::getById(self::$nameIdMappingCache[$cacheKey]);
  153.         }
  154.         // create a tmp object to obtain the id
  155.         $route = new self();
  156.         try {
  157.             $route->getDao()->getByName($name$siteId);
  158.         } catch (NotFoundException $e) {
  159.             return null;
  160.         }
  161.         // to have a singleton in a way. like all instances of Element\ElementInterface do also, like DataObject\AbstractObject
  162.         if ($route->getId() > 0) {
  163.             // add it to the mini-per request cache
  164.             self::$nameIdMappingCache[$cacheKey] = $route->getId();
  165.             return self::getById($route->getId());
  166.         }
  167.         return null;
  168.     }
  169.     /**
  170.      * @return self
  171.      */
  172.     public static function create()
  173.     {
  174.         $route = new self();
  175.         $route->save();
  176.         return $route;
  177.     }
  178.     /**
  179.      * Get the defaults defined in a string as array
  180.      *
  181.      * @return array
  182.      */
  183.     private function getDefaultsArray()
  184.     {
  185.         $defaultsString $this->getDefaults();
  186.         if (empty($defaultsString)) {
  187.             return [];
  188.         }
  189.         $defaults = [];
  190.         $t explode('|'$defaultsString);
  191.         foreach ($t as $v) {
  192.             $d explode('='$v);
  193.             if (strlen($d[0]) > && strlen($d[1]) > 0) {
  194.                 $defaults[$d[0]] = $d[1];
  195.             }
  196.         }
  197.         return $defaults;
  198.     }
  199.     /**
  200.      * @return string
  201.      */
  202.     public function getId()
  203.     {
  204.         return $this->id;
  205.     }
  206.     /**
  207.      * @return string
  208.      */
  209.     public function getPattern()
  210.     {
  211.         return $this->pattern;
  212.     }
  213.     /**
  214.      * @return string
  215.      */
  216.     public function getController()
  217.     {
  218.         return $this->controller;
  219.     }
  220.     /**
  221.      * @return string
  222.      */
  223.     public function getVariables()
  224.     {
  225.         return $this->variables;
  226.     }
  227.     /**
  228.      * @return string
  229.      */
  230.     public function getDefaults()
  231.     {
  232.         return $this->defaults;
  233.     }
  234.     /**
  235.      * @param string $id
  236.      *
  237.      * @return $this
  238.      */
  239.     public function setId($id)
  240.     {
  241.         $this->id $id;
  242.         return $this;
  243.     }
  244.     /**
  245.      * @param string $pattern
  246.      *
  247.      * @return $this
  248.      */
  249.     public function setPattern($pattern)
  250.     {
  251.         $this->pattern $pattern;
  252.         return $this;
  253.     }
  254.     /**
  255.      * @param string $controller
  256.      *
  257.      * @return $this
  258.      */
  259.     public function setController($controller)
  260.     {
  261.         $this->controller $controller;
  262.         return $this;
  263.     }
  264.     /**
  265.      * @param string $variables
  266.      *
  267.      * @return $this
  268.      */
  269.     public function setVariables($variables)
  270.     {
  271.         $this->variables $variables;
  272.         return $this;
  273.     }
  274.     /**
  275.      * @param string $defaults
  276.      *
  277.      * @return $this
  278.      */
  279.     public function setDefaults($defaults)
  280.     {
  281.         $this->defaults $defaults;
  282.         return $this;
  283.     }
  284.     /**
  285.      * @param int $priority
  286.      *
  287.      * @return $this
  288.      */
  289.     public function setPriority($priority)
  290.     {
  291.         $this->priority = (int) $priority;
  292.         return $this;
  293.     }
  294.     /**
  295.      * @return int
  296.      */
  297.     public function getPriority()
  298.     {
  299.         return $this->priority;
  300.     }
  301.     /**
  302.      * @param string $name
  303.      *
  304.      * @return $this
  305.      */
  306.     public function setName($name)
  307.     {
  308.         $this->name $name;
  309.         return $this;
  310.     }
  311.     /**
  312.      * @return string
  313.      */
  314.     public function getName()
  315.     {
  316.         return $this->name;
  317.     }
  318.     /**
  319.      * @param string $reverse
  320.      *
  321.      * @return $this
  322.      */
  323.     public function setReverse($reverse)
  324.     {
  325.         $this->reverse $reverse;
  326.         return $this;
  327.     }
  328.     /**
  329.      * @return string
  330.      */
  331.     public function getReverse()
  332.     {
  333.         return $this->reverse;
  334.     }
  335.     /**
  336.      * @param string|array|null $siteId
  337.      *
  338.      * @return $this
  339.      */
  340.     public function setSiteId($siteId)
  341.     {
  342.         $result = [];
  343.         if (null === $siteId) {
  344.             $siteId = [];
  345.         }
  346.         if (!is_array($siteId)) {
  347.             // backwards compatibility
  348.             $siteIds strlen($siteId) ? explode(','$siteId) : [];
  349.         } else {
  350.             $siteIds $siteId;
  351.         }
  352.         foreach ($siteIds as $siteId) {
  353.             $siteId = (int)$siteId;
  354.             if ($siteId 1) {
  355.                 continue;
  356.             }
  357.             if ($site Site::getById($siteId)) {
  358.                 $result[] = $siteId;
  359.             }
  360.         }
  361.         $this->siteId $result;
  362.         return $this;
  363.     }
  364.     /**
  365.      * @return array
  366.      */
  367.     public function getSiteId()
  368.     {
  369.         if ($this->siteId && !is_array($this->siteId)) {
  370.             $this->siteId explode(','$this->siteId);
  371.         }
  372.         return $this->siteId;
  373.     }
  374.     /**
  375.      * @internal
  376.      *
  377.      * @param array $urlOptions
  378.      * @param bool $encode
  379.      *
  380.      * @return mixed|string
  381.      */
  382.     public function assemble(array $urlOptions = [], $encode true)
  383.     {
  384.         $defaultValues $this->getDefaultsArray();
  385.         // apply values (controller, ... ) from previous match if applicable (only when )
  386.         if (self::$_currentRoute && (self::$_currentRoute->getName() == $this->getName())) {
  387.             $defaultValues array_merge($defaultValuesself::$_currentRoute->_values);
  388.         }
  389.         // merge with defaults
  390.         // merge router.request_context params e.g. "_locale"
  391.         $requestParameters \Pimcore::getContainer()->get('pimcore.routing.router.request_context')->getParameters();
  392.         $urlParams array_merge($defaultValues$requestParameters$urlOptions);
  393.         $parametersInReversePattern = [];
  394.         $parametersGet = [];
  395.         $url $this->getReverse();
  396.         $forbiddenCharacters = ['#'':''?'];
  397.         // check for named variables
  398.         uksort($urlParams, function ($a$b) {
  399.             // order by key length, longer key have priority
  400.             // (%abcd prior %ab, so that %ab doesn't replace %ab in [%ab]cd)
  401.             return strlen($b) - strlen($a);
  402.         });
  403.         $tmpReversePattern $this->getReverse();
  404.         foreach ($urlParams as $key => $param) {
  405.             if (strpos($tmpReversePattern'%' $key) !== false) {
  406.                 $parametersInReversePattern[$key] = $param;
  407.                 // we need to replace the found variable to that it cannot match again a placeholder
  408.                 // eg. %abcd prior %ab if %abcd matches already %ab shouldn't match again on the same placeholder
  409.                 $tmpReversePattern str_replace('%' $key'---'$tmpReversePattern);
  410.             } else {
  411.                 // only append the get parameters if there are defined in $urlOptions
  412.                 if (array_key_exists($key$urlOptions)) {
  413.                     $parametersGet[$key] = $param;
  414.                 }
  415.             }
  416.         }
  417.         $urlEncodeEscapeCharacters '~|urlen' md5(microtime()) . 'code|~';
  418.         // replace named variables
  419.         uksort($parametersInReversePattern, function ($a$b) {
  420.             // order by key length, longer key have priority
  421.             // (%abcd prior %ab, so that %ab doesn't replace %ab in [%ab]cd)
  422.             return strlen($b) - strlen($a);
  423.         });
  424.         foreach ($parametersInReversePattern as $key => $value) {
  425.             $value str_replace($forbiddenCharacters''$value);
  426.             if (strlen($value) > 0) {
  427.                 if ($encode) {
  428.                     $value urlencode_ignore_slash($value);
  429.                 }
  430.                 $value str_replace('%'$urlEncodeEscapeCharacters$value);
  431.                 $url str_replace('%' $key$value$url);
  432.             }
  433.         }
  434.         // remove optional parts
  435.         $url preg_replace("/\{([^\}]+)?%[^\}]+\}/"''$url);
  436.         $url str_replace(['{''}'], ''$url);
  437.         // optional get parameters
  438.         if (!empty($parametersGet)) {
  439.             if ($encode) {
  440.                 $getParams array_urlencode($parametersGet);
  441.             } else {
  442.                 $getParams array_toquerystring($parametersGet);
  443.             }
  444.             $url .= '?' $getParams;
  445.         }
  446.         // convert tmp urlencode escape char back to real escape char
  447.         $url str_replace($urlEncodeEscapeCharacters'%'$url);
  448.         $event = new GenericEvent($this, [
  449.             'frontendPath' => $url,
  450.             'params' => $urlParams,
  451.             'encode' => $encode,
  452.         ]);
  453.         \Pimcore::getEventDispatcher()->dispatch($eventFrontendEvents::STATICROUTE_PATH);
  454.         $url $event->getArgument('frontendPath');
  455.         return $url;
  456.     }
  457.     /**
  458.      * @internal
  459.      *
  460.      * @param string $path
  461.      * @param array $params
  462.      *
  463.      * @return array|bool
  464.      *
  465.      * @throws \Exception
  466.      */
  467.     public function match($path$params = [])
  468.     {
  469.         if (@preg_match($this->getPattern(), $path)) {
  470.             // check for site
  471.             if ($this->getSiteId()) {
  472.                 if (!Site::isSiteRequest()) {
  473.                     return false;
  474.                 }
  475.                 $siteMatched false;
  476.                 $siteIds $this->getSiteId();
  477.                 foreach ($siteIds as $siteId) {
  478.                     if ($siteId == Site::getCurrentSite()->getId()) {
  479.                         $siteMatched true;
  480.                         break;
  481.                     }
  482.                 }
  483.                 if (!$siteMatched) {
  484.                     return false;
  485.                 }
  486.             }
  487.             $variables explode(','$this->getVariables());
  488.             preg_match_all($this->getPattern(), $path$matches);
  489.             if (is_array($matches) && count($matches) > 1) {
  490.                 foreach ($matches as $index => $match) {
  491.                     if (isset($variables[$index 1]) && $variables[$index 1]) {
  492.                         $paramValue urldecode($match[0]);
  493.                         if (!empty($paramValue) || !array_key_exists($variables[$index 1], $params)) {
  494.                             $params[$variables[$index 1]] = $paramValue;
  495.                         }
  496.                     }
  497.                 }
  498.             }
  499.             $params['controller'] = $this->getController();
  500.             // remember for reverse assemble
  501.             $this->_values $params;
  502.             return $params;
  503.         }
  504.         return [];
  505.     }
  506.     /**
  507.      * @return array
  508.      */
  509.     public function getMethods()
  510.     {
  511.         if ($this->methods && is_string($this->methods)) {
  512.             $this->methods explode(','$this->methods);
  513.         }
  514.         return $this->methods;
  515.     }
  516.     /**
  517.      * @param array|string $methods
  518.      *
  519.      * @return $this
  520.      */
  521.     public function setMethods($methods)
  522.     {
  523.         if (is_string($methods)) {
  524.             $methods strlen($methods) ? explode(','$methods) : [];
  525.             $methods array_map('trim'$methods);
  526.         }
  527.         $this->methods $methods;
  528.         return $this;
  529.     }
  530.     /**
  531.      * @param int $modificationDate
  532.      *
  533.      * @return $this
  534.      */
  535.     public function setModificationDate($modificationDate)
  536.     {
  537.         $this->modificationDate = (int) $modificationDate;
  538.         return $this;
  539.     }
  540.     /**
  541.      * @return int|null
  542.      */
  543.     public function getModificationDate()
  544.     {
  545.         return $this->modificationDate;
  546.     }
  547.     /**
  548.      * @param int $creationDate
  549.      *
  550.      * @return $this
  551.      */
  552.     public function setCreationDate($creationDate)
  553.     {
  554.         $this->creationDate = (int) $creationDate;
  555.         return $this;
  556.     }
  557.     /**
  558.      * @return int|null
  559.      */
  560.     public function getCreationDate()
  561.     {
  562.         return $this->creationDate;
  563.     }
  564.     public function __clone()
  565.     {
  566.         if ($this->dao) {
  567.             $this->dao = clone $this->dao;
  568.             $this->dao->setModel($this);
  569.         }
  570.     }
  571. }