Url.php 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework;
  7. use Magento\Framework\App\ObjectManager;
  8. use Magento\Framework\Serialize\Serializer\Json;
  9. use Magento\Framework\Url\HostChecker;
  10. /**
  11. * URL
  12. *
  13. * Properties:
  14. *
  15. * - request
  16. *
  17. * - relative_url: true, false
  18. * - type: 'link', 'skin', 'js', 'media'
  19. * - scope: instanceof \Magento\Framework\Url\ScopeInterface
  20. * - secure: true, false
  21. *
  22. * - scheme: 'http', 'https'
  23. * - user: 'user'
  24. * - password: 'password'
  25. * - host: 'localhost'
  26. * - port: 80, 443
  27. * - base_path: '/dev/magento/'
  28. * - base_script: 'index.php'
  29. *
  30. * - scopeview_path: 'scopeview/'
  31. * - route_path: 'module/controller/action/param1/value1/param2/value2'
  32. * - route_name: 'module'
  33. * - controller_name: 'controller'
  34. * - action_name: 'action'
  35. * - route_params: array('param1'=>'value1', 'param2'=>'value2')
  36. *
  37. * - query: (?)'param1=value1&param2=value2'
  38. * - query_array: array('param1'=>'value1', 'param2'=>'value2')
  39. * - fragment: (#)'fragment-anchor'
  40. *
  41. * @codingStandardsIgnoreStart
  42. * URL structure:
  43. *
  44. * https://user:password@host:443/base_path/[base_script][scopeview_path]route_name/controller_name/action_name/param1/value1?query_param=query_value#fragment
  45. * \__________A___________/\____________________________________B_____________________________________/
  46. * \__________________C___________________/ \__________________D_________________/ \_____E_____/
  47. * \_____________F______________/ \___________________________G______________________/
  48. * \___________________________________________________H____________________________________________________/
  49. * @codingStandardsIgnoreEnd
  50. *
  51. * - A: authority
  52. * - B: path
  53. * - C: absolute_base_url
  54. * - D: action_path
  55. * - E: route_params
  56. * - F: host_url
  57. * - G: route_path
  58. * - H: route_url
  59. * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
  60. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  61. * @SuppressWarnings(PHPMD.TooManyFields)
  62. */
  63. class Url extends \Magento\Framework\DataObject implements \Magento\Framework\UrlInterface
  64. {
  65. /**
  66. * Configuration data cache
  67. *
  68. * @var array
  69. */
  70. protected static $_configDataCache;
  71. /**
  72. * Reserved Route parameter keys
  73. *
  74. * @var array
  75. */
  76. protected $_reservedRouteParams = [
  77. '_scope',
  78. '_type',
  79. '_secure',
  80. '_forced_secure',
  81. '_use_rewrite',
  82. '_nosid',
  83. '_absolute',
  84. '_current',
  85. '_direct',
  86. '_fragment',
  87. '_escape',
  88. '_query',
  89. '_scope_to_url',
  90. ];
  91. /**
  92. * @var string
  93. */
  94. protected $_scopeType;
  95. /**
  96. * Request instance
  97. *
  98. * @var \Magento\Framework\App\RequestInterface
  99. */
  100. protected $_request;
  101. /**
  102. * Use Session ID for generate URL
  103. *
  104. * @var bool
  105. */
  106. protected $_useSession;
  107. /**
  108. * Url security info list
  109. *
  110. * @var \Magento\Framework\Url\SecurityInfoInterface
  111. */
  112. protected $_urlSecurityInfo;
  113. /**
  114. * @var \Magento\Framework\Session\Generic
  115. */
  116. protected $_session;
  117. /**
  118. * @var \Magento\Framework\Session\SidResolverInterface
  119. */
  120. protected $_sidResolver;
  121. /**
  122. * Constructor
  123. *
  124. * @var \Magento\Framework\App\Route\ConfigInterface
  125. */
  126. protected $_routeConfig;
  127. /**
  128. * @var \Magento\Framework\Url\RouteParamsResolverInterface
  129. */
  130. private $_routeParamsResolver;
  131. /**
  132. * @var \Magento\Framework\Url\RouteParamsResolverFactory
  133. */
  134. private $_routeParamsResolverFactory;
  135. /**
  136. * @var \Magento\Framework\Url\ScopeResolverInterface
  137. */
  138. protected $_scopeResolver;
  139. /**
  140. * @var \Magento\Framework\Url\QueryParamsResolverInterface
  141. */
  142. protected $_queryParamsResolver;
  143. /**
  144. * Cache urls requested by getUrl method
  145. *
  146. * @var array
  147. */
  148. private $cacheUrl = [];
  149. /**
  150. * @var \Magento\Framework\App\Config\ScopeConfigInterface
  151. */
  152. protected $_scopeConfig;
  153. /**
  154. * @var \Magento\Framework\Url\RouteParamsPreprocessorInterface
  155. */
  156. protected $routeParamsPreprocessor;
  157. /**
  158. * @var \Magento\Framework\Url\ModifierInterface
  159. */
  160. private $urlModifier;
  161. /**
  162. * @var \Magento\Framework\Escaper
  163. */
  164. private $escaper;
  165. /**
  166. * @var HostChecker
  167. */
  168. private $hostChecker;
  169. /**
  170. * @var Json
  171. */
  172. private $serializer;
  173. /**
  174. * @param \Magento\Framework\App\Route\ConfigInterface $routeConfig
  175. * @param \Magento\Framework\App\RequestInterface $request
  176. * @param \Magento\Framework\Url\SecurityInfoInterface $urlSecurityInfo
  177. * @param \Magento\Framework\Url\ScopeResolverInterface $scopeResolver
  178. * @param \Magento\Framework\Session\Generic $session
  179. * @param \Magento\Framework\Session\SidResolverInterface $sidResolver
  180. * @param \Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolverFactory
  181. * @param \Magento\Framework\Url\QueryParamsResolverInterface $queryParamsResolver
  182. * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
  183. * @param \Magento\Framework\Url\RouteParamsPreprocessorInterface $routeParamsPreprocessor
  184. * @param string $scopeType
  185. * @param array $data
  186. * @param HostChecker|null $hostChecker
  187. * @param Json|null $serializer
  188. * @SuppressWarnings(PHPMD.ExcessiveParameterList)
  189. */
  190. public function __construct(
  191. \Magento\Framework\App\Route\ConfigInterface $routeConfig,
  192. \Magento\Framework\App\RequestInterface $request,
  193. \Magento\Framework\Url\SecurityInfoInterface $urlSecurityInfo,
  194. \Magento\Framework\Url\ScopeResolverInterface $scopeResolver,
  195. \Magento\Framework\Session\Generic $session,
  196. \Magento\Framework\Session\SidResolverInterface $sidResolver,
  197. \Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolverFactory,
  198. \Magento\Framework\Url\QueryParamsResolverInterface $queryParamsResolver,
  199. \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
  200. \Magento\Framework\Url\RouteParamsPreprocessorInterface $routeParamsPreprocessor,
  201. $scopeType,
  202. array $data = [],
  203. HostChecker $hostChecker = null,
  204. Json $serializer = null
  205. ) {
  206. $this->_request = $request;
  207. $this->_routeConfig = $routeConfig;
  208. $this->_urlSecurityInfo = $urlSecurityInfo;
  209. $this->_scopeResolver = $scopeResolver;
  210. $this->_session = $session;
  211. $this->_sidResolver = $sidResolver;
  212. $this->_routeParamsResolverFactory = $routeParamsResolverFactory;
  213. $this->_queryParamsResolver = $queryParamsResolver;
  214. $this->_scopeConfig = $scopeConfig;
  215. $this->routeParamsPreprocessor = $routeParamsPreprocessor;
  216. $this->_scopeType = $scopeType;
  217. $this->hostChecker = $hostChecker ?: \Magento\Framework\App\ObjectManager::getInstance()
  218. ->get(HostChecker::class);
  219. $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class);
  220. parent::__construct($data);
  221. }
  222. /**
  223. * Initialize object data from retrieved url
  224. *
  225. * @param string $url
  226. * @return \Magento\Framework\UrlInterface
  227. */
  228. protected function _parseUrl($url)
  229. {
  230. $data = parse_url($url);
  231. $parts = [
  232. 'scheme' => 'setScheme',
  233. 'host' => 'setHost',
  234. 'port' => 'setPort',
  235. 'user' => 'setUser',
  236. 'pass' => 'setPassword',
  237. 'path' => 'setPath',
  238. 'query' => '_setQuery',
  239. 'fragment' => 'setFragment',
  240. ];
  241. foreach ($parts as $component => $method) {
  242. if (isset($data[$component])) {
  243. $this->{$method}($data[$component]);
  244. }
  245. }
  246. return $this;
  247. }
  248. /**
  249. * Set use session rule
  250. *
  251. * @param bool $useSession
  252. * @return \Magento\Framework\UrlInterface
  253. */
  254. public function setUseSession($useSession)
  255. {
  256. $this->_useSession = (bool) $useSession;
  257. return $this;
  258. }
  259. /**
  260. * Retrieve use session rule
  261. *
  262. * @return bool
  263. * @SuppressWarnings(PHPMD.BooleanGetMethodName)
  264. */
  265. public function getUseSession()
  266. {
  267. if ($this->_useSession === null) {
  268. $this->_useSession = $this->_sidResolver->getUseSessionInUrl();
  269. }
  270. return $this->_useSession;
  271. }
  272. /**
  273. * Retrieve configuration data
  274. *
  275. * @param string $key
  276. * @param string|null $prefix
  277. * @return string
  278. */
  279. public function getConfigData($key, $prefix = null)
  280. {
  281. if ($prefix === null) {
  282. $prefix = 'web/' . ($this->_isSecure() ? 'secure' : 'unsecure') . '/';
  283. }
  284. $path = $prefix . $key;
  285. $cacheId = $this->_getConfigCacheId($path);
  286. if (!isset(self::$_configDataCache[$cacheId])) {
  287. $data = $this->_getConfig($path);
  288. self::$_configDataCache[$cacheId] = $data;
  289. }
  290. return self::$_configDataCache[$cacheId];
  291. }
  292. /**
  293. * Get cache id for config path
  294. *
  295. * @param string $path
  296. * @return string
  297. */
  298. protected function _getConfigCacheId($path)
  299. {
  300. return $this->_getScope()->getCode() . '/' . $path;
  301. }
  302. /**
  303. * Get config data by path
  304. *
  305. * @param string $path
  306. * @return null|string
  307. */
  308. protected function _getConfig($path)
  309. {
  310. return $this->_scopeConfig->getValue(
  311. $path,
  312. $this->_scopeType,
  313. $this->_getScope()
  314. );
  315. }
  316. /**
  317. * Set request
  318. *
  319. * @param \Magento\Framework\App\RequestInterface $request
  320. * @return \Magento\Framework\UrlInterface
  321. */
  322. public function setRequest(\Magento\Framework\App\RequestInterface $request)
  323. {
  324. $this->_request = $request;
  325. return $this;
  326. }
  327. /**
  328. * Zend request object
  329. *
  330. * @return \Magento\Framework\App\RequestInterface
  331. */
  332. protected function _getRequest()
  333. {
  334. return $this->_request;
  335. }
  336. /**
  337. * Retrieve URL type
  338. *
  339. * @return string
  340. */
  341. protected function _getType()
  342. {
  343. if (!$this->getRouteParamsResolver()->hasData('type')) {
  344. $this->getRouteParamsResolver()->setData('type', self::DEFAULT_URL_TYPE);
  345. }
  346. return $this->getRouteParamsResolver()->getType();
  347. }
  348. /**
  349. * Retrieve is secure mode URL
  350. *
  351. * @return bool
  352. */
  353. protected function _isSecure()
  354. {
  355. if ($this->_request->isSecure()) {
  356. if ($this->getRouteParamsResolver()->hasData('secure')) {
  357. return (bool) $this->getRouteParamsResolver()->getData('secure');
  358. }
  359. return true;
  360. }
  361. if ($this->getRouteParamsResolver()->hasData('secure_is_forced')) {
  362. return (bool) $this->getRouteParamsResolver()->getData('secure');
  363. }
  364. if (!$this->_getScope()->isUrlSecure()) {
  365. return false;
  366. }
  367. if (!$this->getRouteParamsResolver()->hasData('secure')) {
  368. if ($this->_getType() == UrlInterface::URL_TYPE_LINK) {
  369. $pathSecure = $this->_urlSecurityInfo->isSecure('/' . $this->_getActionPath());
  370. $this->getRouteParamsResolver()->setData('secure', $pathSecure);
  371. } elseif ($this->_getType() == UrlInterface::URL_TYPE_STATIC) {
  372. $isRequestSecure = $this->_getRequest()->isSecure();
  373. $this->getRouteParamsResolver()->setData('secure', $isRequestSecure);
  374. } else {
  375. $this->getRouteParamsResolver()->setData('secure', true);
  376. }
  377. }
  378. return $this->getRouteParamsResolver()->getData('secure');
  379. }
  380. /**
  381. * Set scope entity
  382. *
  383. * @param mixed $params
  384. * @return \Magento\Framework\UrlInterface
  385. */
  386. public function setScope($params)
  387. {
  388. $this->setData('scope', $this->_scopeResolver->getScope($params));
  389. $this->getRouteParamsResolver()->setScope($this->_scopeResolver->getScope($params));
  390. return $this;
  391. }
  392. /**
  393. * Get current scope for the url instance
  394. *
  395. * @return \Magento\Framework\Url\ScopeInterface
  396. */
  397. protected function _getScope()
  398. {
  399. if (!$this->hasData('scope')) {
  400. $this->setScope(null);
  401. }
  402. return $this->_getData('scope');
  403. }
  404. /**
  405. * Retrieve Base URL
  406. *
  407. * @param array $params
  408. * @return string
  409. */
  410. public function getBaseUrl($params = [])
  411. {
  412. /**
  413. * Original Scope
  414. */
  415. $origScope = $this->_getScope();
  416. if (isset($params['_scope'])) {
  417. $this->setScope($params['_scope']);
  418. }
  419. if (isset($params['_type'])) {
  420. $this->getRouteParamsResolver()->setType($params['_type']);
  421. }
  422. if (isset($params['_secure'])) {
  423. $this->getRouteParamsResolver()->setSecure($params['_secure']);
  424. }
  425. /**
  426. * Add availability support urls without scope code
  427. */
  428. if ($this->_getType() == UrlInterface::URL_TYPE_LINK
  429. && $this->_getRequest()->isDirectAccessFrontendName(
  430. $this->_getRouteFrontName()
  431. )
  432. ) {
  433. $this->getRouteParamsResolver()->setType(UrlInterface::URL_TYPE_DIRECT_LINK);
  434. }
  435. $result = $this->_getScope()->getBaseUrl($this->_getType(), $this->_isSecure());
  436. // setting back the original scope
  437. $this->setScope($origScope);
  438. $this->getRouteParamsResolver()->setType(self::DEFAULT_URL_TYPE);
  439. return $result;
  440. }
  441. /**
  442. * Set Route Parameters
  443. *
  444. * @param string $data
  445. * @return \Magento\Framework\UrlInterface
  446. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  447. */
  448. protected function _setRoutePath($data)
  449. {
  450. if ($this->_getData('route_path') == $data) {
  451. return $this;
  452. }
  453. $this->unsetData('route_path');
  454. $routePieces = explode('/', $data);
  455. $route = array_shift($routePieces);
  456. if ('*' === $route) {
  457. $route = $this->_getRequest()->getRouteName();
  458. }
  459. $this->_setRouteName($route);
  460. $controller = '';
  461. if (!empty($routePieces)) {
  462. $controller = array_shift($routePieces);
  463. if ('*' === $controller) {
  464. $controller = $this->_getRequest()->getControllerName();
  465. }
  466. }
  467. $this->_setControllerName($controller);
  468. $action = '';
  469. if (!empty($routePieces)) {
  470. $action = array_shift($routePieces);
  471. if ('*' === $action) {
  472. $action = $this->_getRequest()->getActionName();
  473. }
  474. }
  475. $this->_setActionName($action);
  476. if (!empty($routePieces)) {
  477. while (!empty($routePieces)) {
  478. $key = array_shift($routePieces);
  479. if (!empty($routePieces)) {
  480. $value = array_shift($routePieces);
  481. $this->getRouteParamsResolver()->setRouteParam($key, $value);
  482. }
  483. }
  484. }
  485. return $this;
  486. }
  487. /**
  488. * Retrieve action path
  489. *
  490. * @return string
  491. */
  492. protected function _getActionPath()
  493. {
  494. if (!$this->_getRouteName()) {
  495. return '';
  496. }
  497. $hasParams = (bool) $this->_getRouteParams();
  498. $path = $this->_getRouteFrontName() . '/';
  499. if ($this->_getControllerName()) {
  500. $path .= $this->_getControllerName() . '/';
  501. } elseif ($hasParams) {
  502. $path .= self::DEFAULT_CONTROLLER_NAME . '/';
  503. }
  504. if ($this->_getActionName()) {
  505. $path .= $this->_getActionName() . '/';
  506. } elseif ($hasParams) {
  507. $path .= self::DEFAULT_ACTION_NAME . '/';
  508. }
  509. return $path;
  510. }
  511. /**
  512. * Retrieve route path
  513. *
  514. * @param array $routeParams
  515. * @return string
  516. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  517. */
  518. protected function _getRoutePath($routeParams = [])
  519. {
  520. if (!$this->hasData('route_path')) {
  521. $routePath = $this->_getRequest()->getAlias(self::REWRITE_REQUEST_PATH_ALIAS);
  522. if (!empty($routeParams['_use_rewrite']) && $routePath !== null) {
  523. $this->setData('route_path', $routePath);
  524. return $routePath;
  525. }
  526. $routePath = $this->_getActionPath();
  527. if ($this->_getRouteParams()) {
  528. foreach ($this->_getRouteParams() as $key => $value) {
  529. if ($value === null || false === $value || '' === $value || !is_scalar($value)) {
  530. continue;
  531. }
  532. $routePath .= $key . '/' . $value . '/';
  533. }
  534. }
  535. $this->setData('route_path', $routePath);
  536. }
  537. return $this->_getData('route_path');
  538. }
  539. /**
  540. * Set route name
  541. *
  542. * @param string $data
  543. * @return \Magento\Framework\UrlInterface
  544. */
  545. protected function _setRouteName($data)
  546. {
  547. if ($this->_getData('route_name') == $data) {
  548. return $this;
  549. }
  550. $this->unsetData('route_front_name')
  551. ->unsetData('route_path')
  552. ->unsetData('controller_name')
  553. ->unsetData('action_name');
  554. $this->_queryParamsResolver->unsetData('secure');
  555. return $this->setData('route_name', $data);
  556. }
  557. /**
  558. * Retrieve route front name
  559. *
  560. * @return string
  561. */
  562. protected function _getRouteFrontName()
  563. {
  564. if (!$this->hasData('route_front_name')) {
  565. $frontName = $this->_routeConfig->getRouteFrontName(
  566. $this->_getRouteName(),
  567. $this->_scopeResolver->getAreaCode()
  568. );
  569. $this->setData('route_front_name', $frontName);
  570. }
  571. return $this->_getData('route_front_name');
  572. }
  573. /**
  574. * Retrieve route name
  575. *
  576. * @param mixed $default
  577. * @return string|null
  578. */
  579. protected function _getRouteName($default = null)
  580. {
  581. return $this->_getData('route_name') ? $this->_getData('route_name') : $default;
  582. }
  583. /**
  584. * Set Controller Name
  585. *
  586. * Reset action name and route path if has change
  587. *
  588. * @param string $data
  589. * @return \Magento\Framework\UrlInterface
  590. */
  591. protected function _setControllerName($data)
  592. {
  593. if ($this->_getData('controller_name') == $data) {
  594. return $this;
  595. }
  596. $this->unsetData('route_path')->unsetData('action_name');
  597. $this->_queryParamsResolver->unsetData('secure');
  598. return $this->setData('controller_name', $data);
  599. }
  600. /**
  601. * Retrieve controller name
  602. *
  603. * @param mixed $default
  604. * @return string|null
  605. */
  606. protected function _getControllerName($default = null)
  607. {
  608. return $this->_getData('controller_name') ? $this->_getData('controller_name') : $default;
  609. }
  610. /**
  611. * Set Action name
  612. * Reseted route path if action name has change
  613. *
  614. * @param string $data
  615. * @return \Magento\Framework\UrlInterface
  616. */
  617. protected function _setActionName($data)
  618. {
  619. if ($this->_getData('action_name') == $data) {
  620. return $this;
  621. }
  622. $this->unsetData('route_path');
  623. $this->setData('action_name', $data);
  624. $this->_queryParamsResolver->unsetData('secure');
  625. return $this;
  626. }
  627. /**
  628. * Retrieve action name
  629. *
  630. * @param mixed $default
  631. * @return string|null
  632. */
  633. protected function _getActionName($default = null)
  634. {
  635. return $this->_getData('action_name') ? $this->_getData('action_name') : $default;
  636. }
  637. /**
  638. * Set route params
  639. *
  640. * @param array $data
  641. * @param boolean $unsetOldParams
  642. * @return \Magento\Framework\UrlInterface
  643. */
  644. protected function _setRouteParams(array $data, $unsetOldParams = true)
  645. {
  646. $this->getRouteParamsResolver()->setRouteParams($data, $unsetOldParams);
  647. return $this;
  648. }
  649. /**
  650. * Retrieve route params
  651. *
  652. * @return array
  653. */
  654. protected function _getRouteParams()
  655. {
  656. return $this->getRouteParamsResolver()->getRouteParams();
  657. }
  658. /**
  659. * Retrieve route URL
  660. *
  661. * @param string $routePath
  662. * @param array $routeParams
  663. * @return string
  664. */
  665. public function getRouteUrl($routePath = null, $routeParams = null)
  666. {
  667. if (filter_var($routePath, FILTER_VALIDATE_URL)) {
  668. return $routePath;
  669. }
  670. $this->getRouteParamsResolver()->unsetData('route_params');
  671. if (isset($routeParams['_direct'])) {
  672. if (is_array($routeParams)) {
  673. $this->_setRouteParams($routeParams, false);
  674. }
  675. return $this->getBaseUrl() . $routeParams['_direct'];
  676. }
  677. $this->_setRoutePath($routePath);
  678. if (is_array($routeParams)) {
  679. $this->_setRouteParams($routeParams, false);
  680. }
  681. return $this->getBaseUrl($routeParams) . $this->_getRoutePath($routeParams);
  682. }
  683. /**
  684. * Add session param
  685. *
  686. * @return \Magento\Framework\UrlInterface
  687. */
  688. public function addSessionParam()
  689. {
  690. $this->setQueryParam(
  691. $this->_sidResolver->getSessionIdQueryParam($this->_session),
  692. $this->_session->getSessionId()
  693. );
  694. return $this;
  695. }
  696. /**
  697. * Set URL query param(s)
  698. *
  699. * @param mixed $data
  700. * @return \Magento\Framework\UrlInterface
  701. */
  702. protected function _setQuery($data)
  703. {
  704. return $this->_queryParamsResolver->setQuery($data);
  705. }
  706. /**
  707. * Get query params part of url
  708. *
  709. * @param bool $escape "&" escape flag
  710. * @return string
  711. */
  712. protected function _getQuery($escape = false)
  713. {
  714. return $this->_queryParamsResolver->getQuery($escape);
  715. }
  716. /**
  717. * Add query Params as array
  718. *
  719. * @param array $data
  720. * @return \Magento\Framework\UrlInterface
  721. */
  722. public function addQueryParams(array $data)
  723. {
  724. $this->_queryParamsResolver->addQueryParams($data);
  725. return $this;
  726. }
  727. /**
  728. * Set query param
  729. *
  730. * @param string $key
  731. * @param mixed $data
  732. * @return \Magento\Framework\UrlInterface
  733. */
  734. public function setQueryParam($key, $data)
  735. {
  736. $this->_queryParamsResolver->setQueryParam($key, $data);
  737. return $this;
  738. }
  739. /**
  740. * Retrieve URL fragment
  741. *
  742. * @return string|null
  743. */
  744. protected function _getFragment()
  745. {
  746. return $this->_getData('fragment');
  747. }
  748. /**
  749. * Build and cache url by requested path and parameters
  750. *
  751. * @param string|null $routePath
  752. * @param array|null $routeParams
  753. * @return string
  754. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  755. * @SuppressWarnings(PHPMD.NPathComplexity)
  756. */
  757. public function getUrl($routePath = null, $routeParams = null)
  758. {
  759. if (filter_var($routePath, FILTER_VALIDATE_URL)) {
  760. return $routePath;
  761. }
  762. $routeParams = $this->routeParamsPreprocessor
  763. ->execute($this->_scopeResolver->getAreaCode(), $routePath, $routeParams);
  764. $isCached = true;
  765. $isArray = is_array($routeParams);
  766. if ($isArray) {
  767. array_walk_recursive(
  768. $routeParams,
  769. function ($item) use (&$isCached) {
  770. if (is_object($item)) {
  771. $isCached = false;
  772. }
  773. }
  774. );
  775. }
  776. if (!$isCached) {
  777. return $this->getUrlModifier()->execute(
  778. $this->createUrl($routePath, $routeParams)
  779. );
  780. }
  781. $cachedParams = $routeParams;
  782. if ($isArray) {
  783. ksort($cachedParams);
  784. }
  785. $cacheKey = sha1($routePath . $this->serializer->serialize($cachedParams));
  786. if (!isset($this->cacheUrl[$cacheKey])) {
  787. $this->cacheUrl[$cacheKey] = $this->getUrlModifier()->execute(
  788. $this->createUrl($routePath, $routeParams)
  789. );
  790. }
  791. return $this->cacheUrl[$cacheKey];
  792. }
  793. /**
  794. * Build url by requested path and parameters
  795. *
  796. * @param string|null $routePath
  797. * @param array|null $routeParams
  798. * @return string
  799. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  800. * @SuppressWarnings(PHPMD.NPathComplexity)
  801. */
  802. private function createUrl($routePath = null, array $routeParams = null)
  803. {
  804. $escapeQuery = false;
  805. $escapeParams = true;
  806. /**
  807. * All system params should be unset before we call getRouteUrl
  808. * this method has condition for adding default controller and action names
  809. * in case when we have params
  810. */
  811. $this->getRouteParamsResolver()->unsetData('secure');
  812. $fragment = null;
  813. if (isset($routeParams['_fragment'])) {
  814. $fragment = $routeParams['_fragment'];
  815. unset($routeParams['_fragment']);
  816. }
  817. if (isset($routeParams['_escape'])) {
  818. $escapeQuery = $routeParams['_escape'];
  819. unset($routeParams['_escape']);
  820. }
  821. if (isset($routeParams['_escape_params'])) {
  822. $escapeParams = $routeParams['_escape_params'];
  823. unset($routeParams['_escape_params']);
  824. }
  825. $this->getRouteParamsResolver()->setData('escape_params', $escapeParams);
  826. $query = null;
  827. if (isset($routeParams['_query'])) {
  828. $this->_queryParamsResolver->setQueryParams([]);
  829. $query = $routeParams['_query'];
  830. unset($routeParams['_query']);
  831. }
  832. $noSid = null;
  833. if (isset($routeParams['_nosid'])) {
  834. $noSid = (bool)$routeParams['_nosid'];
  835. unset($routeParams['_nosid']);
  836. }
  837. $url = $this->getRouteUrl($routePath, $routeParams);
  838. /**
  839. * Apply query params, need call after getRouteUrl for rewrite _current values
  840. */
  841. if ($query !== null) {
  842. if (is_string($query)) {
  843. $this->_setQuery($query);
  844. } elseif (is_array($query)) {
  845. $this->addQueryParams($query, !empty($routeParams['_current']));
  846. }
  847. if ($query === false) {
  848. $this->addQueryParams([]);
  849. }
  850. }
  851. if ($noSid !== true) {
  852. $this->_prepareSessionUrl($url);
  853. }
  854. $query = $this->_getQuery($escapeQuery);
  855. if ($query) {
  856. $mark = strpos($url, '?') === false ? '?' : ($escapeQuery ? '&amp;' : '&');
  857. $url .= $mark . $query;
  858. $this->_queryParamsResolver->unsetData('query');
  859. $this->_queryParamsResolver->unsetData('query_params');
  860. }
  861. if ($fragment !== null) {
  862. $url .= '#' . $this->getEscaper()->encodeUrlParam($fragment);
  863. }
  864. $this->getRouteParamsResolver()->unsetData('secure');
  865. $this->getRouteParamsResolver()->unsetData('escape_params');
  866. return $url;
  867. }
  868. /**
  869. * Check and add session id to URL
  870. *
  871. * @param string $url
  872. *
  873. * @return \Magento\Framework\UrlInterface
  874. */
  875. protected function _prepareSessionUrl($url)
  876. {
  877. if (!$this->getUseSession()) {
  878. return $this;
  879. }
  880. $sessionId = $this->_session->getSessionIdForHost($url);
  881. if ($this->_sidResolver->getUseSessionVar() && !$sessionId) {
  882. $this->setQueryParam('___SID', $this->_isSecure() ? 'S' : 'U');
  883. } elseif ($sessionId) {
  884. $this->setQueryParam($this->_sidResolver->getSessionIdQueryParam($this->_session), $sessionId);
  885. }
  886. return $this;
  887. }
  888. /**
  889. * Rebuild URL to handle the case when session ID was changed
  890. *
  891. * @param string $url
  892. * @return string
  893. */
  894. public function getRebuiltUrl($url)
  895. {
  896. $this->_parseUrl($url);
  897. $port = $this->getPort();
  898. if ($port) {
  899. $port = ':' . $port;
  900. } else {
  901. $port = '';
  902. }
  903. $url = $this->getScheme() . '://' . $this->getHost() . $port . $this->getPath();
  904. $this->_prepareSessionUrl($url);
  905. $query = $this->_getQuery();
  906. if ($query) {
  907. $url .= '?' . $query;
  908. }
  909. $fragment = $this->_getFragment();
  910. if ($fragment) {
  911. $url .= '#' . $this->getEscaper()->encodeUrlParam($fragment);
  912. }
  913. return $url;
  914. }
  915. /**
  916. * Escape (enclosure) URL string
  917. *
  918. * @param string $value
  919. * @return string
  920. * @deprecated 101.0.0
  921. */
  922. public function escape($value)
  923. {
  924. $value = str_replace('"', '%22', $value);
  925. $value = str_replace("'", '%27', $value);
  926. $value = str_replace('>', '%3E', $value);
  927. $value = str_replace('<', '%3C', $value);
  928. return $value;
  929. }
  930. /**
  931. * Build url by direct url and parameters
  932. *
  933. * @param string $url
  934. * @param array $params
  935. * @return string
  936. */
  937. public function getDirectUrl($url, $params = [])
  938. {
  939. $params['_direct'] = $url;
  940. return $this->getUrl('', $params);
  941. }
  942. /**
  943. * Replace Session ID value in URL
  944. *
  945. * @param string $html
  946. * @return string
  947. */
  948. public function sessionUrlVar($html)
  949. {
  950. return preg_replace_callback(
  951. '#(\?|&amp;|&)___SID=([SU])(&amp;|&)?#',
  952. // @codingStandardsIgnoreStart
  953. /**
  954. * Callback function for session replace
  955. *
  956. * @param array $match
  957. * @return string
  958. */
  959. // @codingStandardsIgnoreEnd
  960. function ($match) {
  961. if ($this->useSessionIdForUrl($match[2] == 'S' ? true : false)) {
  962. return $match[1] . $this->_sidResolver->getSessionIdQueryParam($this->_session) . '='
  963. . $this->_session->getSessionId() . (isset($match[3]) ? $match[3] : '');
  964. } else {
  965. if ($match[1] == '?') {
  966. return isset($match[3]) ? '?' : '';
  967. } elseif ($match[1] == '&amp;' || $match[1] == '&') {
  968. return $match[3] ?? '';
  969. }
  970. }
  971. },
  972. $html
  973. );
  974. }
  975. /**
  976. * Check and return use SID for URL
  977. *
  978. * @param bool $secure
  979. * @return bool
  980. */
  981. public function useSessionIdForUrl($secure = false)
  982. {
  983. $key = 'use_session_id_for_url_' . (int)$secure;
  984. if ($this->getData($key) === null) {
  985. $httpHost = $this->_request->getHttpHost();
  986. $urlHost = parse_url(
  987. $this->_getScope()->getBaseUrl(UrlInterface::URL_TYPE_LINK, $secure),
  988. PHP_URL_HOST
  989. );
  990. if ($httpHost != $urlHost) {
  991. $this->setData($key, true);
  992. } else {
  993. $this->setData($key, false);
  994. }
  995. }
  996. return $this->getData($key);
  997. }
  998. /**
  999. * Check if users originated URL is one of the domain URLs assigned to scopes
  1000. *
  1001. * @return boolean
  1002. */
  1003. public function isOwnOriginUrl()
  1004. {
  1005. return $this->hostChecker->isOwnOrigin($this->_request->getServer('HTTP_REFERER'));
  1006. }
  1007. /**
  1008. * Return frontend redirect URL with SID and other session parameters if any
  1009. *
  1010. * @param string $url
  1011. *
  1012. * @return string
  1013. */
  1014. public function getRedirectUrl($url)
  1015. {
  1016. $this->_prepareSessionUrl($url);
  1017. $query = $this->_getQuery(false);
  1018. if ($query) {
  1019. $url .= (strpos($url, '?') === false ? '?' : '&') . $query;
  1020. }
  1021. return $url;
  1022. }
  1023. /**
  1024. * Retrieve current url
  1025. *
  1026. * @return string
  1027. */
  1028. public function getCurrentUrl()
  1029. {
  1030. $httpHostWithPort = $this->_request->getHttpHost(false);
  1031. $httpHostWithPort = explode(':', $httpHostWithPort);
  1032. $httpHost = isset($httpHostWithPort[0]) ? $httpHostWithPort[0] : '';
  1033. $port = '';
  1034. if (isset($httpHostWithPort[1])) {
  1035. $defaultPorts = [
  1036. \Magento\Framework\App\Request\Http::DEFAULT_HTTP_PORT,
  1037. \Magento\Framework\App\Request\Http::DEFAULT_HTTPS_PORT,
  1038. ];
  1039. if (!in_array($httpHostWithPort[1], $defaultPorts)) {
  1040. /** Custom port */
  1041. $port = ':' . $httpHostWithPort[1];
  1042. }
  1043. }
  1044. return $this->_request->getScheme() . '://' . $httpHost . $port . $this->_request->getRequestUri();
  1045. }
  1046. /**
  1047. * Get Route Params Resolver
  1048. *
  1049. * @return Url\RouteParamsResolverInterface
  1050. */
  1051. protected function getRouteParamsResolver()
  1052. {
  1053. if (!$this->_routeParamsResolver) {
  1054. $this->_routeParamsResolver = $this->_routeParamsResolverFactory->create();
  1055. }
  1056. return $this->_routeParamsResolver;
  1057. }
  1058. /**
  1059. * Gets URL modifier.
  1060. *
  1061. * @return \Magento\Framework\Url\ModifierInterface
  1062. * @deprecated 101.0.0
  1063. */
  1064. private function getUrlModifier()
  1065. {
  1066. if ($this->urlModifier === null) {
  1067. $this->urlModifier = \Magento\Framework\App\ObjectManager::getInstance()->get(
  1068. \Magento\Framework\Url\ModifierInterface::class
  1069. );
  1070. }
  1071. return $this->urlModifier;
  1072. }
  1073. /**
  1074. * Get escaper
  1075. *
  1076. * @return Escaper
  1077. * @deprecated 101.0.0
  1078. */
  1079. private function getEscaper()
  1080. {
  1081. if ($this->escaper == null) {
  1082. $this->escaper = \Magento\Framework\App\ObjectManager::getInstance()
  1083. ->get(\Magento\Framework\Escaper::class);
  1084. }
  1085. return $this->escaper;
  1086. }
  1087. }