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

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