Template.php 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\View\Element;
  7. use Magento\Framework\App\Filesystem\DirectoryList;
  8. use Magento\Framework\Filesystem;
  9. /**
  10. * Standard Magento block.
  11. * Should be used when you declare a block in frontend area layout handle.
  12. *
  13. * Avoid extending this class.
  14. *
  15. * If you need custom presentation logic in your blocks, use this class as block, and declare
  16. * custom view models in block arguments in layout handle file.
  17. *
  18. * Example:
  19. * <block name="my.block" class="Magento\Backend\Block\Template" template="My_Module::template.phtml" >
  20. * <arguments>
  21. * <argument name="viewModel" xsi:type="object">My\Module\ViewModel\Custom</argument>
  22. * </arguments>
  23. * </block>
  24. *
  25. * @api
  26. * @SuppressWarnings(PHPMD.NumberOfChildren)
  27. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  28. * @since 100.0.2
  29. */
  30. class Template extends AbstractBlock
  31. {
  32. /**
  33. * Config path to 'Allow Symlinks' template settings
  34. */
  35. const XML_PATH_TEMPLATE_ALLOW_SYMLINK = 'dev/template/allow_symlink';
  36. /**
  37. * Assigned variables for view
  38. *
  39. * @var array
  40. */
  41. protected $_viewVars = [];
  42. /**
  43. * Base URL
  44. *
  45. * @var string
  46. */
  47. protected $_baseUrl;
  48. /**
  49. * JS URL
  50. *
  51. * @var string
  52. */
  53. protected $_jsUrl;
  54. /**
  55. * Is allowed symlinks flag
  56. *
  57. * @var bool
  58. */
  59. protected $_allowSymlinks;
  60. /**
  61. * Filesystem instance
  62. *
  63. * @var Filesystem
  64. */
  65. protected $_filesystem;
  66. /**
  67. * Path to template file in theme.
  68. *
  69. * @var string
  70. */
  71. protected $_template;
  72. /**
  73. * Template engine pool
  74. *
  75. * @var \Magento\Framework\View\TemplateEnginePool
  76. */
  77. protected $templateEnginePool;
  78. /**
  79. * Store manager
  80. *
  81. * @var \Magento\Store\Model\StoreManagerInterface
  82. */
  83. protected $_storeManager;
  84. /**
  85. * Application state
  86. *
  87. * @var \Magento\Framework\App\State
  88. */
  89. protected $_appState;
  90. /**
  91. * Root directory instance
  92. *
  93. * @var \Magento\Framework\Filesystem\Directory\ReadInterface
  94. */
  95. protected $directory;
  96. /**
  97. * Media directory instance
  98. *
  99. * @var \Magento\Framework\Filesystem\Directory\ReadInterface
  100. */
  101. private $mediaDirectory;
  102. /**
  103. * Template context
  104. *
  105. * @var \Magento\Framework\View\Element\BlockInterface
  106. */
  107. protected $templateContext;
  108. /**
  109. * @var \Magento\Framework\View\Page\Config
  110. */
  111. protected $pageConfig;
  112. /**
  113. * @var \Magento\Framework\View\Element\Template\File\Resolver
  114. */
  115. protected $resolver;
  116. /**
  117. * @var \Magento\Framework\View\Element\Template\File\Validator
  118. */
  119. protected $validator;
  120. /**
  121. * Constructor
  122. *
  123. * @param Template\Context $context
  124. * @param array $data
  125. */
  126. public function __construct(Template\Context $context, array $data = [])
  127. {
  128. $this->validator = $context->getValidator();
  129. $this->resolver = $context->getResolver();
  130. $this->_filesystem = $context->getFilesystem();
  131. $this->templateEnginePool = $context->getEnginePool();
  132. $this->_storeManager = $context->getStoreManager();
  133. $this->_appState = $context->getAppState();
  134. $this->templateContext = $this;
  135. $this->pageConfig = $context->getPageConfig();
  136. parent::__construct($context, $data);
  137. }
  138. /**
  139. * Set template context. Sets the object that should represent $block in template
  140. *
  141. * @param \Magento\Framework\View\Element\BlockInterface $templateContext
  142. * @return void
  143. */
  144. public function setTemplateContext($templateContext)
  145. {
  146. $this->templateContext = $templateContext;
  147. }
  148. /**
  149. * Internal constructor, that is called from real constructor
  150. * @return void
  151. */
  152. protected function _construct()
  153. {
  154. parent::_construct();
  155. /*
  156. * In case template was passed through constructor
  157. * we assign it to block's property _template
  158. * Mainly for those cases when block created
  159. * not via \Magento\Framework\View\Model\LayoutInterface::addBlock()
  160. */
  161. if ($this->hasData('template')) {
  162. $this->setTemplate($this->getData('template'));
  163. }
  164. }
  165. /**
  166. * Get relevant path to template
  167. *
  168. * @return string
  169. */
  170. public function getTemplate()
  171. {
  172. return $this->_template;
  173. }
  174. /**
  175. * Set path to template used for generating block's output.
  176. *
  177. * @param string $template
  178. * @return $this
  179. */
  180. public function setTemplate($template)
  181. {
  182. $this->_template = $template;
  183. return $this;
  184. }
  185. /**
  186. * Get absolute path to template
  187. *
  188. * @param string|null $template
  189. * @return string|bool
  190. */
  191. public function getTemplateFile($template = null)
  192. {
  193. $params = ['module' => $this->getModuleName()];
  194. $area = $this->getArea();
  195. if ($area) {
  196. $params['area'] = $area;
  197. }
  198. return $this->resolver->getTemplateFileName($template ?: $this->getTemplate(), $params);
  199. }
  200. /**
  201. * Get design area
  202. *
  203. * @return string
  204. */
  205. public function getArea()
  206. {
  207. return $this->_getData('area') ? $this->_getData('area') : $this->_appState->getAreaCode();
  208. }
  209. /**
  210. * Assign variable
  211. *
  212. * @param string|array $key
  213. * @param mixed $value
  214. * @return $this
  215. */
  216. public function assign($key, $value = null)
  217. {
  218. if (is_array($key)) {
  219. foreach ($key as $subKey => $subValue) {
  220. $this->assign($subKey, $subValue);
  221. }
  222. } else {
  223. $this->_viewVars[$key] = $value;
  224. }
  225. return $this;
  226. }
  227. /**
  228. * Retrieve block view from file (template)
  229. *
  230. * @param string $fileName
  231. * @return string
  232. */
  233. public function fetchView($fileName)
  234. {
  235. $relativeFilePath = $this->getRootDirectory()->getRelativePath($fileName);
  236. \Magento\Framework\Profiler::start(
  237. 'TEMPLATE:' . $fileName,
  238. ['group' => 'TEMPLATE', 'file_name' => $relativeFilePath]
  239. );
  240. if ($this->validator->isValid($fileName)) {
  241. $extension = pathinfo($fileName, PATHINFO_EXTENSION);
  242. $templateEngine = $this->templateEnginePool->get($extension);
  243. $html = $templateEngine->render($this->templateContext, $fileName, $this->_viewVars);
  244. } else {
  245. $html = '';
  246. $templatePath = $fileName ?: $this->getTemplate();
  247. $errorMessage = "Invalid template file: '{$templatePath}' in module: '{$this->getModuleName()}'"
  248. . " block's name: '{$this->getNameInLayout()}'";
  249. if ($this->_appState->getMode() === \Magento\Framework\App\State::MODE_DEVELOPER) {
  250. throw new \Magento\Framework\Exception\ValidatorException(
  251. new \Magento\Framework\Phrase(
  252. $errorMessage
  253. )
  254. );
  255. }
  256. $this->_logger->critical($errorMessage);
  257. }
  258. \Magento\Framework\Profiler::stop('TEMPLATE:' . $fileName);
  259. return $html;
  260. }
  261. /**
  262. * Render block HTML
  263. *
  264. * @return string
  265. */
  266. protected function _toHtml()
  267. {
  268. if (!$this->getTemplate()) {
  269. return '';
  270. }
  271. return $this->fetchView($this->getTemplateFile());
  272. }
  273. /**
  274. * Get base url of the application
  275. *
  276. * @return string
  277. */
  278. public function getBaseUrl()
  279. {
  280. if (!$this->_baseUrl) {
  281. $this->_baseUrl = $this->_urlBuilder->getBaseUrl();
  282. }
  283. return $this->_baseUrl;
  284. }
  285. /**
  286. * Get data from specified object
  287. *
  288. * @param \Magento\Framework\DataObject $object
  289. * @param string $key
  290. * @return mixed
  291. */
  292. public function getObjectData(\Magento\Framework\DataObject $object, $key)
  293. {
  294. return $object->getDataUsingMethod((string)$key);
  295. }
  296. /**
  297. * Get cache key informative items
  298. *
  299. * @return array
  300. */
  301. public function getCacheKeyInfo()
  302. {
  303. return [
  304. 'BLOCK_TPL',
  305. $this->_storeManager->getStore()->getCode(),
  306. $this->getTemplateFile(),
  307. 'base_url' => $this->getBaseUrl(),
  308. 'template' => $this->getTemplate()
  309. ];
  310. }
  311. /**
  312. * Instantiates filesystem directory
  313. *
  314. * @return \Magento\Framework\Filesystem\Directory\ReadInterface
  315. */
  316. protected function getRootDirectory()
  317. {
  318. if (null === $this->directory) {
  319. $this->directory = $this->_filesystem->getDirectoryRead(DirectoryList::ROOT);
  320. }
  321. return $this->directory;
  322. }
  323. /**
  324. * Get media directory
  325. *
  326. * @return \Magento\Framework\Filesystem\Directory\Read
  327. */
  328. protected function getMediaDirectory()
  329. {
  330. if (!$this->mediaDirectory) {
  331. $this->mediaDirectory = $this->_filesystem->getDirectoryRead(DirectoryList::MEDIA);
  332. }
  333. return $this->mediaDirectory;
  334. }
  335. }