Config.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\View\Page;
  7. use Magento\Framework\App;
  8. use Magento\Framework\App\Area;
  9. use Magento\Framework\View;
  10. /**
  11. * An API for page configuration
  12. *
  13. * Has methods for managing properties specific to web pages:
  14. * - title
  15. * - related documents, linked static assets in particular
  16. * - meta info
  17. * - root element properties
  18. * - etc...
  19. *
  20. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  21. * @SuppressWarnings(PHPMD.TooManyFields)
  22. *
  23. * @api
  24. * @since 100.0.2
  25. */
  26. class Config
  27. {
  28. /**#@+
  29. * Constants of available types
  30. */
  31. const ELEMENT_TYPE_BODY = 'body';
  32. const ELEMENT_TYPE_HTML = 'html';
  33. const ELEMENT_TYPE_HEAD = 'head';
  34. /**#@-*/
  35. const META_DESCRIPTION = 'description';
  36. const META_CONTENT_TYPE = 'content_type';
  37. const META_MEDIA_TYPE = 'media_type';
  38. const META_CHARSET = 'charset';
  39. const META_TITLE = 'title';
  40. const META_KEYWORDS = 'keywords';
  41. const META_ROBOTS = 'robots';
  42. const META_X_UI_COMPATIBLE = 'x_ua_compatible';
  43. /**
  44. * Constant body attribute class
  45. */
  46. const BODY_ATTRIBUTE_CLASS = 'class';
  47. /**
  48. * Constant html language attribute
  49. */
  50. const HTML_ATTRIBUTE_LANG = 'lang';
  51. /**
  52. * Allowed group of types
  53. *
  54. * @var array
  55. */
  56. protected $allowedTypes = [
  57. self::ELEMENT_TYPE_BODY,
  58. self::ELEMENT_TYPE_HTML,
  59. self::ELEMENT_TYPE_HEAD,
  60. ];
  61. /**
  62. * @var Title
  63. */
  64. protected $title;
  65. /**
  66. * Asset service
  67. *
  68. * @var \Magento\Framework\View\Asset\Repository
  69. */
  70. protected $assetRepo;
  71. /**
  72. * @var \Magento\Framework\View\Asset\GroupedCollection
  73. */
  74. protected $pageAssets;
  75. /**
  76. * @var string[][]
  77. */
  78. protected $elements = [];
  79. /**
  80. * @var string
  81. */
  82. protected $pageLayout;
  83. /**
  84. * @var \Magento\Framework\App\Config\ScopeConfigInterface
  85. */
  86. protected $scopeConfig;
  87. /**
  88. * @var \Magento\Framework\View\Page\FaviconInterface
  89. */
  90. protected $favicon;
  91. /**
  92. * @var \Magento\Framework\Locale\ResolverInterface
  93. */
  94. protected $localeResolver;
  95. /**
  96. * @var \Magento\Framework\View\Layout\BuilderInterface
  97. */
  98. protected $builder;
  99. /**
  100. * @var array
  101. */
  102. protected $includes;
  103. /**
  104. * @var array
  105. */
  106. protected $metadata = [
  107. 'charset' => null,
  108. 'media_type' => null,
  109. 'content_type' => null,
  110. 'description' => null,
  111. 'keywords' => null,
  112. 'robots' => null,
  113. 'title' => null,
  114. ];
  115. /**
  116. * @var \Magento\Framework\App\State
  117. */
  118. private $areaResolver;
  119. /**
  120. * @var bool
  121. */
  122. private $isIncludesAvailable;
  123. /**
  124. * This getter serves as a workaround to add this dependency to this class without breaking constructor structure.
  125. *
  126. * @return \Magento\Framework\App\State
  127. *
  128. * @deprecated 100.0.7
  129. */
  130. private function getAreaResolver()
  131. {
  132. if ($this->areaResolver === null) {
  133. $this->areaResolver = \Magento\Framework\App\ObjectManager::getInstance()
  134. ->get(\Magento\Framework\App\State::class);
  135. }
  136. return $this->areaResolver;
  137. }
  138. /**
  139. * @param \Magento\Framework\View\Asset\Repository $assetRepo
  140. * @param \Magento\Framework\View\Asset\GroupedCollection $pageAssets
  141. * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
  142. * @param \Magento\Framework\View\Page\FaviconInterface $favicon
  143. * @param Title $title
  144. * @param \Magento\Framework\Locale\ResolverInterface $localeResolver
  145. * @param bool $isIncludesAvailable
  146. */
  147. public function __construct(
  148. View\Asset\Repository $assetRepo,
  149. View\Asset\GroupedCollection $pageAssets,
  150. App\Config\ScopeConfigInterface $scopeConfig,
  151. View\Page\FaviconInterface $favicon,
  152. Title $title,
  153. \Magento\Framework\Locale\ResolverInterface $localeResolver,
  154. $isIncludesAvailable = true
  155. ) {
  156. $this->assetRepo = $assetRepo;
  157. $this->pageAssets = $pageAssets;
  158. $this->scopeConfig = $scopeConfig;
  159. $this->favicon = $favicon;
  160. $this->title = $title;
  161. $this->localeResolver = $localeResolver;
  162. $this->isIncludesAvailable = $isIncludesAvailable;
  163. $this->setElementAttribute(
  164. self::ELEMENT_TYPE_HTML,
  165. self::HTML_ATTRIBUTE_LANG,
  166. strstr($this->localeResolver->getLocale(), '_', true)
  167. );
  168. }
  169. /**
  170. * Set builder.
  171. *
  172. * @param View\Layout\BuilderInterface $builder
  173. * @return $this
  174. */
  175. public function setBuilder(View\Layout\BuilderInterface $builder)
  176. {
  177. $this->builder = $builder;
  178. return $this;
  179. }
  180. /**
  181. * Build page config from page configurations
  182. *
  183. * @return void
  184. */
  185. protected function build()
  186. {
  187. if (!empty($this->builder)) {
  188. $this->builder->build();
  189. }
  190. }
  191. /**
  192. * Public build action
  193. *
  194. * TODO Will be eliminated in MAGETWO-28359
  195. *
  196. * @return void
  197. */
  198. public function publicBuild()
  199. {
  200. $this->build();
  201. }
  202. /**
  203. * Retrieve title element text (encoded)
  204. *
  205. * @return Title
  206. */
  207. public function getTitle()
  208. {
  209. $this->build();
  210. return $this->title;
  211. }
  212. /**
  213. * Set metadata.
  214. *
  215. * @param string $name
  216. * @param string $content
  217. * @return void
  218. */
  219. public function setMetadata($name, $content)
  220. {
  221. $this->build();
  222. $this->metadata[$name] = htmlspecialchars($content);
  223. }
  224. /**
  225. * Returns metadata
  226. *
  227. * @return array
  228. */
  229. public function getMetadata()
  230. {
  231. $this->build();
  232. return $this->metadata;
  233. }
  234. /**
  235. * Set content type
  236. *
  237. * @param string $contentType
  238. * @return void
  239. */
  240. public function setContentType($contentType)
  241. {
  242. $this->setMetadata(self::META_CONTENT_TYPE, $contentType);
  243. }
  244. /**
  245. * Retrieve Content Type
  246. *
  247. * @return string
  248. */
  249. public function getContentType()
  250. {
  251. $this->build();
  252. if (strtolower($this->metadata[self::META_CONTENT_TYPE]) === 'auto') {
  253. $this->metadata[self::META_CONTENT_TYPE] = $this->getMediaType() . '; charset=' . $this->getCharset();
  254. }
  255. return $this->metadata[self::META_CONTENT_TYPE];
  256. }
  257. /**
  258. * Set media type
  259. *
  260. * @param string $mediaType
  261. * @return void
  262. */
  263. public function setMediaType($mediaType)
  264. {
  265. $this->setMetadata(self::META_MEDIA_TYPE, $mediaType);
  266. }
  267. /**
  268. * Retrieve Media Type
  269. *
  270. * @return string
  271. */
  272. public function getMediaType()
  273. {
  274. $this->build();
  275. if (empty($this->metadata[self::META_MEDIA_TYPE])) {
  276. $this->metadata[self::META_MEDIA_TYPE] = $this->scopeConfig->getValue(
  277. 'design/head/default_media_type',
  278. \Magento\Store\Model\ScopeInterface::SCOPE_STORE
  279. );
  280. }
  281. return $this->metadata[self::META_MEDIA_TYPE];
  282. }
  283. /**
  284. * Set charset
  285. *
  286. * @param string $charset
  287. * @return void
  288. */
  289. public function setCharset($charset)
  290. {
  291. $this->setMetadata(self::META_CHARSET, $charset);
  292. }
  293. /**
  294. * Retrieve Charset
  295. *
  296. * @return string
  297. */
  298. public function getCharset()
  299. {
  300. $this->build();
  301. if (empty($this->metadata[self::META_CHARSET])) {
  302. $this->metadata[self::META_CHARSET] = $this->scopeConfig->getValue(
  303. 'design/head/default_charset',
  304. \Magento\Store\Model\ScopeInterface::SCOPE_STORE
  305. );
  306. }
  307. return $this->metadata[self::META_CHARSET];
  308. }
  309. /**
  310. * Set description
  311. *
  312. * @param string $description
  313. * @return void
  314. */
  315. public function setDescription($description)
  316. {
  317. $this->setMetadata(self::META_DESCRIPTION, $description);
  318. }
  319. /**
  320. * Retrieve content for description tag
  321. *
  322. * @return string
  323. */
  324. public function getDescription()
  325. {
  326. $this->build();
  327. if (empty($this->metadata[self::META_DESCRIPTION])) {
  328. $this->metadata[self::META_DESCRIPTION] = $this->scopeConfig->getValue(
  329. 'design/head/default_description',
  330. \Magento\Store\Model\ScopeInterface::SCOPE_STORE
  331. );
  332. }
  333. return $this->metadata[self::META_DESCRIPTION];
  334. }
  335. /**
  336. * Set meta title
  337. *
  338. * @param string $title
  339. * @since 101.0.6
  340. */
  341. public function setMetaTitle($title)
  342. {
  343. $this->setMetadata(self::META_TITLE, $title);
  344. }
  345. /**
  346. * Retrieve meta title
  347. *
  348. * @return string
  349. * @since 101.0.6
  350. */
  351. public function getMetaTitle()
  352. {
  353. $this->build();
  354. if (empty($this->metadata[self::META_TITLE])) {
  355. return '';
  356. }
  357. return $this->metadata[self::META_TITLE];
  358. }
  359. /**
  360. * Set keywords
  361. *
  362. * @param string $keywords
  363. * @return void
  364. */
  365. public function setKeywords($keywords)
  366. {
  367. $this->setMetadata(self::META_KEYWORDS, $keywords);
  368. }
  369. /**
  370. * Retrieve content for keywords tag
  371. *
  372. * @return string
  373. */
  374. public function getKeywords()
  375. {
  376. $this->build();
  377. if (empty($this->metadata[self::META_KEYWORDS])) {
  378. $this->metadata[self::META_KEYWORDS] = $this->scopeConfig->getValue(
  379. 'design/head/default_keywords',
  380. \Magento\Store\Model\ScopeInterface::SCOPE_STORE
  381. );
  382. }
  383. return $this->metadata[self::META_KEYWORDS];
  384. }
  385. /**
  386. * Set robots content
  387. *
  388. * @param string $robots
  389. * @return void
  390. */
  391. public function setRobots($robots)
  392. {
  393. $this->setMetadata(self::META_ROBOTS, $robots);
  394. }
  395. /**
  396. * Retrieve URL to robots file
  397. *
  398. * @return string
  399. * @throws \Magento\Framework\Exception\LocalizedException
  400. */
  401. public function getRobots()
  402. {
  403. if ($this->getAreaResolver()->getAreaCode() !== Area::AREA_FRONTEND) {
  404. return 'NOINDEX,NOFOLLOW';
  405. }
  406. $this->build();
  407. if (empty($this->metadata[self::META_ROBOTS])) {
  408. $this->metadata[self::META_ROBOTS] = $this->scopeConfig->getValue(
  409. 'design/search_engine_robots/default_robots',
  410. \Magento\Store\Model\ScopeInterface::SCOPE_STORE
  411. );
  412. }
  413. return $this->metadata[self::META_ROBOTS];
  414. }
  415. /**
  416. * Returns collection of the assets
  417. *
  418. * @return \Magento\Framework\View\Asset\GroupedCollection
  419. */
  420. public function getAssetCollection()
  421. {
  422. $this->build();
  423. return $this->pageAssets;
  424. }
  425. /**
  426. * Add asset to page content
  427. *
  428. * @param string $file
  429. * @param array $properties
  430. * @param string|null $name
  431. * @return $this
  432. */
  433. public function addPageAsset($file, array $properties = [], $name = null)
  434. {
  435. $asset = $this->assetRepo->createAsset($file);
  436. $name = $name ?: $file;
  437. $this->pageAssets->add($name, $asset, $properties);
  438. return $this;
  439. }
  440. /**
  441. * Add remote page asset
  442. *
  443. * @param string $url
  444. * @param string $contentType
  445. * @param array $properties
  446. * @param string|null $name
  447. * @return $this
  448. */
  449. public function addRemotePageAsset($url, $contentType, array $properties = [], $name = null)
  450. {
  451. $remoteAsset = $this->assetRepo->createRemoteAsset($url, $contentType);
  452. $name = $name ?: $url;
  453. $this->pageAssets->add($name, $remoteAsset, $properties);
  454. return $this;
  455. }
  456. /**
  457. * Add RSS element
  458. *
  459. * @param string $title
  460. * @param string $href
  461. * @return $this
  462. */
  463. public function addRss($title, $href)
  464. {
  465. $remoteAsset = $this->assetRepo->createRemoteAsset((string)$href, 'unknown');
  466. $this->pageAssets->add(
  467. "link/{$href}",
  468. $remoteAsset,
  469. ['attributes' => 'rel="alternate" type="application/rss+xml" title="' . $title . '"']
  470. );
  471. return $this;
  472. }
  473. /**
  474. * Add CSS class to page body tag
  475. *
  476. * @param string $className
  477. * @return $this
  478. */
  479. public function addBodyClass($className)
  480. {
  481. $className = preg_replace('#[^a-z0-9-_]+#', '-', strtolower($className));
  482. $bodyClasses = $this->getElementAttribute(self::ELEMENT_TYPE_BODY, self::BODY_ATTRIBUTE_CLASS);
  483. $bodyClasses = $bodyClasses ? explode(' ', $bodyClasses) : [];
  484. $bodyClasses[] = $className;
  485. $bodyClasses = array_unique($bodyClasses);
  486. $this->setElementAttribute(
  487. self::ELEMENT_TYPE_BODY,
  488. self::BODY_ATTRIBUTE_CLASS,
  489. implode(' ', $bodyClasses)
  490. );
  491. return $this;
  492. }
  493. /**
  494. * Set additional element attribute
  495. *
  496. * @param string $elementType
  497. * @param string $attribute
  498. * @param mixed $value
  499. * @return $this
  500. * @throws \Magento\Framework\Exception\LocalizedException
  501. */
  502. public function setElementAttribute($elementType, $attribute, $value)
  503. {
  504. $this->build();
  505. if (array_search($elementType, $this->allowedTypes) === false) {
  506. throw new \Magento\Framework\Exception\LocalizedException(
  507. new \Magento\Framework\Phrase('%1 isn\'t allowed', [$elementType])
  508. );
  509. }
  510. $this->elements[$elementType][$attribute] = $value;
  511. return $this;
  512. }
  513. /**
  514. * Retrieve additional element attribute
  515. *
  516. * @param string $elementType
  517. * @param string $attribute
  518. * @return null
  519. */
  520. public function getElementAttribute($elementType, $attribute)
  521. {
  522. $this->build();
  523. return $this->elements[$elementType][$attribute] ?? null;
  524. }
  525. /**
  526. * Returns element attributes
  527. *
  528. * @param string $elementType
  529. * @return string[]
  530. */
  531. public function getElementAttributes($elementType)
  532. {
  533. $this->build();
  534. return $this->elements[$elementType] ?? [];
  535. }
  536. /**
  537. * Set page layout
  538. *
  539. * @param string $handle
  540. * @return $this
  541. */
  542. public function setPageLayout($handle)
  543. {
  544. $this->pageLayout = $handle;
  545. return $this;
  546. }
  547. /**
  548. * Return current page layout
  549. *
  550. * @return string
  551. */
  552. public function getPageLayout()
  553. {
  554. return $this->pageLayout;
  555. }
  556. /**
  557. * Returns favicon file
  558. *
  559. * @return string
  560. */
  561. public function getFaviconFile()
  562. {
  563. return $this->favicon->getFaviconFile();
  564. }
  565. /**
  566. * Returns default favicon
  567. *
  568. * @return string
  569. */
  570. public function getDefaultFavicon()
  571. {
  572. return $this->favicon->getDefaultFavicon();
  573. }
  574. /**
  575. * Get miscellaneous scripts/styles to be included in head before head closing tag
  576. *
  577. * @return string
  578. */
  579. public function getIncludes()
  580. {
  581. if (empty($this->includes) && $this->isIncludesAvailable) {
  582. $this->includes = $this->scopeConfig->getValue(
  583. 'design/head/includes',
  584. \Magento\Store\Model\ScopeInterface::SCOPE_STORE
  585. );
  586. }
  587. return $this->includes;
  588. }
  589. }