20 class Merge implements \Magento\Framework\View\Layout\ProcessorInterface
100 private $pageLayoutFileSource;
112 private $layoutCacheKey;
163 private $readFactory;
184 \
Magento\Framework\
Url\ScopeResolverInterface $scopeResolver,
185 \
Magento\Framework\View\
File\CollectorInterface $fileSource,
186 \
Magento\Framework\View\
File\CollectorInterface $pageLayoutFileSource,
190 \Psr\Log\LoggerInterface
$logger,
196 $this->theme = $theme ?: $design->getDesignTheme();
197 $this->scope = $scopeResolver->getScope();
198 $this->fileSource = $fileSource;
199 $this->pageLayoutFileSource = $pageLayoutFileSource;
200 $this->appState = $appState;
202 $this->layoutValidator = $validator;
204 $this->readFactory = $readFactory;
206 $this->layoutCacheKey = $layoutCacheKey
218 if (!in_array($update, $this->updates)) {
219 $this->updates[] = $update;
241 return implode(
'', $this->updates);
252 if (is_array($handleName)) {
253 foreach ($handleName as
$name) {
254 $this->handles[
$name] = 1;
257 $this->handles[$handleName] = 1;
270 unset($this->handles[$handleName]);
281 return array_keys($this->handles);
293 $handlesAdded =
false;
294 foreach ($handlesToTry as $handleName) {
301 $handlesAdded =
true;
303 return $handlesAdded;
334 if ($fullLayoutXml->xpath(
"layout[@id='{$handle}']")) {
358 return $nodes ? reset($nodes) :
null;
391 '(@design_abstraction="' . self::DESIGN_ABSTRACTION_PAGE_LAYOUT .
392 '" or @design_abstraction="' . self::DESIGN_ABSTRACTION_CUSTOM .
'")',
394 $xpath =
'/layouts/*[' . implode(
' or ', $conditions) .
']';
397 foreach ($nodes as $node) {
398 $name = $node->getAttribute(
'id');
401 'label' => (string)
new \
Magento\Framework\
Phrase((
string)$node->getAttribute(
'label')),
402 'design_abstraction' => $node->getAttribute(
'design_abstraction'),
418 return $node ? $node->getAttribute(
'type') :
null;
433 throw new \Magento\Framework\Exception\LocalizedException(
434 new \
Magento\Framework\
Phrase(
'Invalid layout update handle')
445 $this->pageLayout = $this->
_loadCache($cacheIdPageLayout);
473 $layoutStr =
'<handle id="handle">' . $layout .
'</handle>';
477 }
catch (\Exception $e) {
478 $messages = $this->layoutValidator->getMessages();
482 'Cache file with merged layout: ' . $cacheId
502 .
'<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' 516 return simplexml_load_string($xmlString, \
Magento\Framework\View\
Layout\Element::class);
527 if (!isset($this->allHandles[
$handle])) {
532 }
elseif ($this->allHandles[
$handle] == $this->handleProcessing
535 $this->logger->info(
'Cyclic dependency in merged layout for handle: ' .
$handle);
548 $_profilerKey =
'layout_package_update:' .
$handle;
549 \Magento\Framework\Profiler::start($_profilerKey);
551 foreach ($layout->xpath(
"*[self::handle or self::layout][@id='{$handle}']") as $updateXml) {
553 $updateInnerXml = $updateXml->innerXml();
557 \Magento\Framework\Profiler::stop($_profilerKey);
570 $_profilerKey =
'layout_db_update: ' .
$handle;
571 \Magento\Framework\Profiler::start($_profilerKey);
574 \Magento\Framework\Profiler::stop($_profilerKey);
577 $updateStr =
'<update_xml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' .
583 $updateInnerXml = $updateXml->innerXml();
587 \Magento\Framework\Profiler::stop($_profilerKey);
588 return (
bool)$updateStr;
616 if ($this->subst ===
null) {
618 'baseUrl' => $this->scope->getBaseUrl(),
622 foreach ($placeholders as $key =>
$value) {
623 $this->subst[
'from'][] =
'{{' . $key .
'}}';
624 $this->subst[
'to'][] =
$value;
627 return str_replace($this->subst[
'from'], $this->subst[
'to'], $xmlString);
651 foreach ($updateXml->children() as $child) {
652 if (strtolower($child->getName()) ==
'update' && isset($child[
'handle'])) {
653 $this->
_merge((
string)$child[
'handle']);
656 if (isset($updateXml[
'layout'])) {
657 $this->pageLayout = (string)$updateXml[
'layout'];
669 if ($this->layoutUpdatesCache) {
677 $result = $this->_loadFileLayoutUpdatesXml();
680 $this->layoutUpdatesCache =
$result;
692 return "LAYOUT_{$this->theme->getArea()}_STORE{$this->scope->getId()}_{$this->theme->getId()}{$suffix}";
703 return $this->cache->load($cacheId);
716 $this->cache->save(
$data, $cacheId, $cacheTags,
null);
725 protected function _loadFileLayoutUpdatesXml()
729 $updateFiles = $this->fileSource->getFiles($theme,
'*.xml');
730 $updateFiles = array_merge($updateFiles, $this->pageLayoutFileSource->getFiles($theme,
'*.xml'));
731 $useErrors = libxml_use_internal_errors(
true);
732 foreach ($updateFiles as $file) {
734 $fileReader = $this->readFactory->create($file->getFilename(),
DriverPool::FILE);
735 $fileStr = $fileReader->readAll($file->getName());
740 $xmlErrors = $this->getXmlErrors(libxml_get_errors());
745 "Theme layout update file '%1' is not valid.\n%2",
747 $file->getFilename(),
748 implode(
"\n", $xmlErrors)
753 libxml_clear_errors();
756 if (!$file->isBase() && $fileXml->xpath(self::XPATH_HANDLE_DECLARATION)) {
757 throw new \Magento\Framework\Exception\LocalizedException(
759 'Theme layout update file \'%1\' must not declare page types.',
760 [$file->getFileName()]
764 $handleName = basename($file->getFilename(),
'.xml');
765 $tagName = $fileXml->getName() ===
'layout' ?
'layout' :
'handle';
767 $handleStr =
'<' . $tagName . $handleAttributes .
'>' . $fileXml->innerXml() .
'</' . $tagName .
'>';
768 $layoutStr .= $handleStr;
770 libxml_use_internal_errors($useErrors);
771 $layoutStr =
'<layouts xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' . $layoutStr .
'</layouts>';
786 sprintf(
"Theme layout update file '%s' is not valid.\n%s",
$fileName, implode(
"\n", $xmlErrors))
796 private function getXmlErrors($libXmlErrors)
799 if (count($libXmlErrors)) {
800 foreach ($libXmlErrors as $error) {
801 $errors[] =
"{$error->message} Line: {$error->line}";
821 throw new \Magento\Framework\Exception\LocalizedException(
823 'Unable to find a physical ancestor for a theme \'%1\'.',
840 foreach ($node->attributes() as $attributeName => $attributeValue) {
841 $result .=
' ' . $attributeName .
'="' . $attributeValue .
'"';
860 $containerNodes = $this->
asSimplexml()->xpath(
'//container');
862 foreach ($containerNodes as $oneContainerNode) {
863 $label = $oneContainerNode->getAttribute(
'label');
880 $this->layoutUpdatesCache =
null;
888 if (!isset($abstraction[
'design_abstraction'])) {
899 if (!isset($abstraction[
'design_abstraction'])) {
932 $layoutCacheKeys = $this->layoutCacheKey->getCacheKeys();
_loadXmlString($xmlString)
const PAGE_LAYOUT_CACHE_SUFFIX
_fetchPackageLayoutUpdates($handle)
elseif(isset( $params[ 'redirect_parent']))
pageHandleExists($handleName)
const DESIGN_ABSTRACTION_CUSTOM
_logXmlErrors($fileName, $xmlErrors)
removeHandle($handleName)
_fetchRecursiveUpdates($updateXml)
_getPhysicalTheme(\Magento\Framework\View\Design\ThemeInterface $theme)
validateUpdate($handle, $updateXml)
const DESIGN_ABSTRACTION_PAGE_LAYOUT
getDbUpdateString($handle)
getPageHandleType($handleName)
__construct(\Magento\Framework\View\DesignInterface $design, \Magento\Framework\Url\ScopeResolverInterface $scopeResolver, \Magento\Framework\View\File\CollectorInterface $fileSource, \Magento\Framework\View\File\CollectorInterface $pageLayoutFileSource, \Magento\Framework\App\State $appState, \Magento\Framework\Cache\FrontendInterface $cache, \Magento\Framework\View\Model\Layout\Update\Validator $validator, \Psr\Log\LoggerInterface $logger, ReadFactory $readFactory, \Magento\Framework\View\Design\ThemeInterface $theme=null, $cacheSuffix='', LayoutCacheKeyInterface $layoutCacheKey=null)
isCustomerDesignAbstraction(array $abstraction)
const XPATH_HANDLE_DECLARATION
_getPageHandleNode($handleName)
generateCacheId($suffix='')
_saveCache($data, $cacheId, array $cacheTags=[])
_renderXmlAttributes(\SimpleXMLElement $node)
_fetchDbLayoutUpdates($handle)
addPageHandles(array $handlesToTry)
_validateMergedLayout($cacheId, $layout)
getAllDesignAbstractions()
isPageLayoutDesignAbstraction(array $abstraction)
getFileLayoutUpdatesXml()
foreach( $_productCollection as $_product)() ?>" class $info
const LAYOUT_SCHEMA_MERGED
_substitutePlaceholders($xmlString)
if(!isset($_GET['name'])) $name