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

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.         $defaults = [];
  186.         $t explode('|'$this->getDefaults());
  187.         foreach ($t as $v) {
  188.             $d explode('='$v);
  189.             if (strlen($d[0]) > && strlen($d[1]) > 0) {
  190.                 $defaults[$d[0]] = $d[1];
  191.             }
  192.         }
  193.         return $defaults;
  194.     }
  195.     /**
  196.      * @return string
  197.      */
  198.     public function getId()
  199.     {
  200.         return $this->id;
  201.     }
  202.     /**
  203.      * @return string
  204.      */
  205.     public function getPattern()
  206.     {
  207.         return $this->pattern;
  208.     }
  209.     /**
  210.      * @return string
  211.      */
  212.     public function getController()
  213.     {
  214.         return $this->controller;
  215.     }
  216.     /**
  217.      * @return string
  218.      */
  219.     public function getVariables()
  220.     {
  221.         return $this->variables;
  222.     }
  223.     /**
  224.      * @return string
  225.      */
  226.     public function getDefaults()
  227.     {
  228.         return $this->defaults;
  229.     }
  230.     /**
  231.      * @param string $id
  232.      *
  233.      * @return $this
  234.      */
  235.     public function setId($id)
  236.     {
  237.         $this->id $id;
  238.         return $this;
  239.     }
  240.     /**
  241.      * @param string $pattern
  242.      *
  243.      * @return $this
  244.      */
  245.     public function setPattern($pattern)
  246.     {
  247.         $this->pattern $pattern;
  248.         return $this;
  249.     }
  250.     /**
  251.      * @param string $controller
  252.      *
  253.      * @return $this
  254.      */
  255.     public function setController($controller)
  256.     {
  257.         $this->controller $controller;
  258.         return $this;
  259.     }
  260.     /**
  261.      * @param string $variables
  262.      *
  263.      * @return $this
  264.      */
  265.     public function setVariables($variables)
  266.     {
  267.         $this->variables $variables;
  268.         return $this;
  269.     }
  270.     /**
  271.      * @param string $defaults
  272.      *
  273.      * @return $this
  274.      */
  275.     public function setDefaults($defaults)
  276.     {
  277.         $this->defaults $defaults;
  278.         return $this;
  279.     }
  280.     /**
  281.      * @param int $priority
  282.      *
  283.      * @return $this
  284.      */
  285.     public function setPriority($priority)
  286.     {
  287.         $this->priority = (int) $priority;
  288.         return $this;
  289.     }
  290.     /**
  291.      * @return int
  292.      */
  293.     public function getPriority()
  294.     {
  295.         return $this->priority;
  296.     }
  297.     /**
  298.      * @param string $name
  299.      *
  300.      * @return $this
  301.      */
  302.     public function setName($name)
  303.     {
  304.         $this->name $name;
  305.         return $this;
  306.     }
  307.     /**
  308.      * @return string
  309.      */
  310.     public function getName()
  311.     {
  312.         return $this->name;
  313.     }
  314.     /**
  315.      * @param string $reverse
  316.      *
  317.      * @return $this
  318.      */
  319.     public function setReverse($reverse)
  320.     {
  321.         $this->reverse $reverse;
  322.         return $this;
  323.     }
  324.     /**
  325.      * @return string
  326.      */
  327.     public function getReverse()
  328.     {
  329.         return $this->reverse;
  330.     }
  331.     /**
  332.      * @param string|array $siteId
  333.      *
  334.      * @return $this
  335.      */
  336.     public function setSiteId($siteId)
  337.     {
  338.         $result = [];
  339.         if (!is_array($siteId)) {
  340.             // backwards compatibility
  341.             $siteIds strlen($siteId) ? explode(','$siteId) : [];
  342.         } else {
  343.             $siteIds $siteId;
  344.         }
  345.         foreach ($siteIds as $siteId) {
  346.             $siteId = (int)$siteId;
  347.             if ($siteId 1) {
  348.                 continue;
  349.             }
  350.             if ($site Site::getById($siteId)) {
  351.                 $result[] = $siteId;
  352.             }
  353.         }
  354.         $this->siteId $result;
  355.         return $this;
  356.     }
  357.     /**
  358.      * @return array
  359.      */
  360.     public function getSiteId()
  361.     {
  362.         if ($this->siteId && !is_array($this->siteId)) {
  363.             $this->siteId explode(','$this->siteId);
  364.         }
  365.         return $this->siteId;
  366.     }
  367.     /**
  368.      * @internal
  369.      *
  370.      * @param array $urlOptions
  371.      * @param bool $encode
  372.      *
  373.      * @return mixed|string
  374.      */
  375.     public function assemble(array $urlOptions = [], $encode true)
  376.     {
  377.         $defaultValues $this->getDefaultsArray();
  378.         // apply values (controller, ... ) from previous match if applicable (only when )
  379.         if (self::$_currentRoute && (self::$_currentRoute->getName() == $this->getName())) {
  380.             $defaultValues array_merge($defaultValuesself::$_currentRoute->_values);
  381.         }
  382.         // merge with defaults
  383.         // merge router.request_context params e.g. "_locale"
  384.         $requestParameters \Pimcore::getContainer()->get('pimcore.routing.router.request_context')->getParameters();
  385.         $urlParams array_merge($defaultValues$requestParameters$urlOptions);
  386.         $parametersInReversePattern = [];
  387.         $parametersGet = [];
  388.         $url $this->getReverse();
  389.         $forbiddenCharacters = ['#'':''?'];
  390.         // check for named variables
  391.         uksort($urlParams, function ($a$b) {
  392.             // order by key length, longer key have priority
  393.             // (%abcd prior %ab, so that %ab doesn't replace %ab in [%ab]cd)
  394.             return strlen($b) - strlen($a);
  395.         });
  396.         $tmpReversePattern $this->getReverse();
  397.         foreach ($urlParams as $key => $param) {
  398.             if (strpos($tmpReversePattern'%' $key) !== false) {
  399.                 $parametersInReversePattern[$key] = $param;
  400.                 // we need to replace the found variable to that it cannot match again a placeholder
  401.                 // eg. %abcd prior %ab if %abcd matches already %ab shouldn't match again on the same placeholder
  402.                 $tmpReversePattern str_replace('%' $key'---'$tmpReversePattern);
  403.             } else {
  404.                 // only append the get parameters if there are defined in $urlOptions
  405.                 if (array_key_exists($key$urlOptions)) {
  406.                     $parametersGet[$key] = $param;
  407.                 }
  408.             }
  409.         }
  410.         $urlEncodeEscapeCharacters '~|urlen' md5(microtime()) . 'code|~';
  411.         // replace named variables
  412.         uksort($parametersInReversePattern, function ($a$b) {
  413.             // order by key length, longer key have priority
  414.             // (%abcd prior %ab, so that %ab doesn't replace %ab in [%ab]cd)
  415.             return strlen($b) - strlen($a);
  416.         });
  417.         foreach ($parametersInReversePattern as $key => $value) {
  418.             $value str_replace($forbiddenCharacters''$value);
  419.             if (strlen($value) > 0) {
  420.                 if ($encode) {
  421.                     $value urlencode_ignore_slash($value);
  422.                 }
  423.                 $value str_replace('%'$urlEncodeEscapeCharacters$value);
  424.                 $url str_replace('%' $key$value$url);
  425.             }
  426.         }
  427.         // remove optional parts
  428.         $url preg_replace("/\{([^\}]+)?%[^\}]+\}/"''$url);
  429.         $url str_replace(['{''}'], ''$url);
  430.         // optional get parameters
  431.         if (!empty($parametersGet)) {
  432.             if ($encode) {
  433.                 $getParams array_urlencode($parametersGet);
  434.             } else {
  435.                 $getParams array_toquerystring($parametersGet);
  436.             }
  437.             $url .= '?' $getParams;
  438.         }
  439.         // convert tmp urlencode escape char back to real escape char
  440.         $url str_replace($urlEncodeEscapeCharacters'%'$url);
  441.         $event = new GenericEvent($this, [
  442.             'frontendPath' => $url,
  443.             'params' => $urlParams,
  444.             'encode' => $encode,
  445.         ]);
  446.         \Pimcore::getEventDispatcher()->dispatch($eventFrontendEvents::STATICROUTE_PATH);
  447.         $url $event->getArgument('frontendPath');
  448.         return $url;
  449.     }
  450.     /**
  451.      * @internal
  452.      *
  453.      * @param string $path
  454.      * @param array $params
  455.      *
  456.      * @return array|bool
  457.      *
  458.      * @throws \Exception
  459.      */
  460.     public function match($path$params = [])
  461.     {
  462.         if (@preg_match($this->getPattern(), $path)) {
  463.             // check for site
  464.             if ($this->getSiteId()) {
  465.                 if (!Site::isSiteRequest()) {
  466.                     return false;
  467.                 }
  468.                 $siteMatched false;
  469.                 $siteIds $this->getSiteId();
  470.                 foreach ($siteIds as $siteId) {
  471.                     if ($siteId == Site::getCurrentSite()->getId()) {
  472.                         $siteMatched true;
  473.                         break;
  474.                     }
  475.                 }
  476.                 if (!$siteMatched) {
  477.                     return false;
  478.                 }
  479.             }
  480.             $variables explode(','$this->getVariables());
  481.             preg_match_all($this->getPattern(), $path$matches);
  482.             if (is_array($matches) && count($matches) > 1) {
  483.                 foreach ($matches as $index => $match) {
  484.                     if (isset($variables[$index 1]) && $variables[$index 1]) {
  485.                         $paramValue urldecode($match[0]);
  486.                         if (!empty($paramValue) || !array_key_exists($variables[$index 1], $params)) {
  487.                             $params[$variables[$index 1]] = $paramValue;
  488.                         }
  489.                     }
  490.                 }
  491.             }
  492.             $params['controller'] = $this->getController();
  493.             // remember for reverse assemble
  494.             $this->_values $params;
  495.             return $params;
  496.         }
  497.         return [];
  498.     }
  499.     /**
  500.      * @return array
  501.      */
  502.     public function getMethods()
  503.     {
  504.         if ($this->methods && is_string($this->methods)) {
  505.             $this->methods explode(','$this->methods);
  506.         }
  507.         return $this->methods;
  508.     }
  509.     /**
  510.      * @param array|string $methods
  511.      *
  512.      * @return $this
  513.      */
  514.     public function setMethods($methods)
  515.     {
  516.         if (is_string($methods)) {
  517.             $methods strlen($methods) ? explode(','$methods) : [];
  518.             $methods array_map('trim'$methods);
  519.         }
  520.         $this->methods $methods;
  521.         return $this;
  522.     }
  523.     /**
  524.      * @param int $modificationDate
  525.      *
  526.      * @return $this
  527.      */
  528.     public function setModificationDate($modificationDate)
  529.     {
  530.         $this->modificationDate = (int) $modificationDate;
  531.         return $this;
  532.     }
  533.     /**
  534.      * @return int|null
  535.      */
  536.     public function getModificationDate()
  537.     {
  538.         return $this->modificationDate;
  539.     }
  540.     /**
  541.      * @param int $creationDate
  542.      *
  543.      * @return $this
  544.      */
  545.     public function setCreationDate($creationDate)
  546.     {
  547.         $this->creationDate = (int) $creationDate;
  548.         return $this;
  549.     }
  550.     /**
  551.      * @return int|null
  552.      */
  553.     public function getCreationDate()
  554.     {
  555.         return $this->creationDate;
  556.     }
  557.     public function __clone()
  558.     {
  559.         if ($this->dao) {
  560.             $this->dao = clone $this->dao;
  561.             $this->dao->setModel($this);
  562.         }
  563.     }
  564. }