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

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 $siteId
  337.      *
  338.      * @return $this
  339.      */
  340.     public function setSiteId($siteId)
  341.     {
  342.         $result = [];
  343.         if (!is_array($siteId)) {
  344.             // backwards compatibility
  345.             $siteIds strlen($siteId) ? explode(','$siteId) : [];
  346.         } else {
  347.             $siteIds $siteId;
  348.         }
  349.         foreach ($siteIds as $siteId) {
  350.             $siteId = (int)$siteId;
  351.             if ($siteId 1) {
  352.                 continue;
  353.             }
  354.             if ($site Site::getById($siteId)) {
  355.                 $result[] = $siteId;
  356.             }
  357.         }
  358.         $this->siteId $result;
  359.         return $this;
  360.     }
  361.     /**
  362.      * @return array
  363.      */
  364.     public function getSiteId()
  365.     {
  366.         if ($this->siteId && !is_array($this->siteId)) {
  367.             $this->siteId explode(','$this->siteId);
  368.         }
  369.         return $this->siteId;
  370.     }
  371.     /**
  372.      * @internal
  373.      *
  374.      * @param array $urlOptions
  375.      * @param bool $encode
  376.      *
  377.      * @return mixed|string
  378.      */
  379.     public function assemble(array $urlOptions = [], $encode true)
  380.     {
  381.         $defaultValues $this->getDefaultsArray();
  382.         // apply values (controller, ... ) from previous match if applicable (only when )
  383.         if (self::$_currentRoute && (self::$_currentRoute->getName() == $this->getName())) {
  384.             $defaultValues array_merge($defaultValuesself::$_currentRoute->_values);
  385.         }
  386.         // merge with defaults
  387.         // merge router.request_context params e.g. "_locale"
  388.         $requestParameters \Pimcore::getContainer()->get('pimcore.routing.router.request_context')->getParameters();
  389.         $urlParams array_merge($defaultValues$requestParameters$urlOptions);
  390.         $parametersInReversePattern = [];
  391.         $parametersGet = [];
  392.         $url $this->getReverse();
  393.         $forbiddenCharacters = ['#'':''?'];
  394.         // check for named variables
  395.         uksort($urlParams, function ($a$b) {
  396.             // order by key length, longer key have priority
  397.             // (%abcd prior %ab, so that %ab doesn't replace %ab in [%ab]cd)
  398.             return strlen($b) - strlen($a);
  399.         });
  400.         $tmpReversePattern $this->getReverse();
  401.         foreach ($urlParams as $key => $param) {
  402.             if (strpos($tmpReversePattern'%' $key) !== false) {
  403.                 $parametersInReversePattern[$key] = $param;
  404.                 // we need to replace the found variable to that it cannot match again a placeholder
  405.                 // eg. %abcd prior %ab if %abcd matches already %ab shouldn't match again on the same placeholder
  406.                 $tmpReversePattern str_replace('%' $key'---'$tmpReversePattern);
  407.             } else {
  408.                 // only append the get parameters if there are defined in $urlOptions
  409.                 if (array_key_exists($key$urlOptions)) {
  410.                     $parametersGet[$key] = $param;
  411.                 }
  412.             }
  413.         }
  414.         $urlEncodeEscapeCharacters '~|urlen' md5(microtime()) . 'code|~';
  415.         // replace named variables
  416.         uksort($parametersInReversePattern, function ($a$b) {
  417.             // order by key length, longer key have priority
  418.             // (%abcd prior %ab, so that %ab doesn't replace %ab in [%ab]cd)
  419.             return strlen($b) - strlen($a);
  420.         });
  421.         foreach ($parametersInReversePattern as $key => $value) {
  422.             $value str_replace($forbiddenCharacters''$value);
  423.             if (strlen($value) > 0) {
  424.                 if ($encode) {
  425.                     $value urlencode_ignore_slash($value);
  426.                 }
  427.                 $value str_replace('%'$urlEncodeEscapeCharacters$value);
  428.                 $url str_replace('%' $key$value$url);
  429.             }
  430.         }
  431.         // remove optional parts
  432.         $url preg_replace("/\{([^\}]+)?%[^\}]+\}/"''$url);
  433.         $url str_replace(['{''}'], ''$url);
  434.         // optional get parameters
  435.         if (!empty($parametersGet)) {
  436.             if ($encode) {
  437.                 $getParams array_urlencode($parametersGet);
  438.             } else {
  439.                 $getParams array_toquerystring($parametersGet);
  440.             }
  441.             $url .= '?' $getParams;
  442.         }
  443.         // convert tmp urlencode escape char back to real escape char
  444.         $url str_replace($urlEncodeEscapeCharacters'%'$url);
  445.         $event = new GenericEvent($this, [
  446.             'frontendPath' => $url,
  447.             'params' => $urlParams,
  448.             'encode' => $encode,
  449.         ]);
  450.         \Pimcore::getEventDispatcher()->dispatch($eventFrontendEvents::STATICROUTE_PATH);
  451.         $url $event->getArgument('frontendPath');
  452.         return $url;
  453.     }
  454.     /**
  455.      * @internal
  456.      *
  457.      * @param string $path
  458.      * @param array $params
  459.      *
  460.      * @return array|bool
  461.      *
  462.      * @throws \Exception
  463.      */
  464.     public function match($path$params = [])
  465.     {
  466.         if (@preg_match($this->getPattern(), $path)) {
  467.             // check for site
  468.             if ($this->getSiteId()) {
  469.                 if (!Site::isSiteRequest()) {
  470.                     return false;
  471.                 }
  472.                 $siteMatched false;
  473.                 $siteIds $this->getSiteId();
  474.                 foreach ($siteIds as $siteId) {
  475.                     if ($siteId == Site::getCurrentSite()->getId()) {
  476.                         $siteMatched true;
  477.                         break;
  478.                     }
  479.                 }
  480.                 if (!$siteMatched) {
  481.                     return false;
  482.                 }
  483.             }
  484.             $variables explode(','$this->getVariables());
  485.             preg_match_all($this->getPattern(), $path$matches);
  486.             if (is_array($matches) && count($matches) > 1) {
  487.                 foreach ($matches as $index => $match) {
  488.                     if (isset($variables[$index 1]) && $variables[$index 1]) {
  489.                         $paramValue urldecode($match[0]);
  490.                         if (!empty($paramValue) || !array_key_exists($variables[$index 1], $params)) {
  491.                             $params[$variables[$index 1]] = $paramValue;
  492.                         }
  493.                     }
  494.                 }
  495.             }
  496.             $params['controller'] = $this->getController();
  497.             // remember for reverse assemble
  498.             $this->_values $params;
  499.             return $params;
  500.         }
  501.         return [];
  502.     }
  503.     /**
  504.      * @return array
  505.      */
  506.     public function getMethods()
  507.     {
  508.         if ($this->methods && is_string($this->methods)) {
  509.             $this->methods explode(','$this->methods);
  510.         }
  511.         return $this->methods;
  512.     }
  513.     /**
  514.      * @param array|string $methods
  515.      *
  516.      * @return $this
  517.      */
  518.     public function setMethods($methods)
  519.     {
  520.         if (is_string($methods)) {
  521.             $methods strlen($methods) ? explode(','$methods) : [];
  522.             $methods array_map('trim'$methods);
  523.         }
  524.         $this->methods $methods;
  525.         return $this;
  526.     }
  527.     /**
  528.      * @param int $modificationDate
  529.      *
  530.      * @return $this
  531.      */
  532.     public function setModificationDate($modificationDate)
  533.     {
  534.         $this->modificationDate = (int) $modificationDate;
  535.         return $this;
  536.     }
  537.     /**
  538.      * @return int|null
  539.      */
  540.     public function getModificationDate()
  541.     {
  542.         return $this->modificationDate;
  543.     }
  544.     /**
  545.      * @param int $creationDate
  546.      *
  547.      * @return $this
  548.      */
  549.     public function setCreationDate($creationDate)
  550.     {
  551.         $this->creationDate = (int) $creationDate;
  552.         return $this;
  553.     }
  554.     /**
  555.      * @return int|null
  556.      */
  557.     public function getCreationDate()
  558.     {
  559.         return $this->creationDate;
  560.     }
  561.     public function __clone()
  562.     {
  563.         if ($this->dao) {
  564.             $this->dao = clone $this->dao;
  565.             $this->dao->setModel($this);
  566.         }
  567.     }
  568. }