diff --git a/app/code/Magento/Theme/Model/PageLayout/Config/Builder.php b/app/code/Magento/Theme/Model/PageLayout/Config/Builder.php index 13b8aa23073ce..e528f9e88d8a4 100644 --- a/app/code/Magento/Theme/Model/PageLayout/Config/Builder.php +++ b/app/code/Magento/Theme/Model/PageLayout/Config/Builder.php @@ -5,25 +5,38 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Theme\Model\PageLayout\Config; +use Magento\Framework\App\Cache\Type\Layout; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\View\Model\PageLayout\Config\BuilderInterface; +use Magento\Framework\View\PageLayout\ConfigFactory; +use Magento\Framework\View\PageLayout\File\Collector\Aggregated; +use Magento\Theme\Model\ResourceModel\Theme\Collection; +use Magento\Theme\Model\Theme\Data; +use Magento\Framework\Serialize\SerializerInterface; + /** * Page layout config builder */ -class Builder implements \Magento\Framework\View\Model\PageLayout\Config\BuilderInterface +class Builder implements BuilderInterface { + const CACHE_KEY_LAYOUTS = 'THEME_LAYOUTS_FILES_MERGED'; + /** - * @var \Magento\Framework\View\PageLayout\ConfigFactory + * @var ConfigFactory */ protected $configFactory; /** - * @var \Magento\Framework\View\PageLayout\File\Collector\Aggregated + * @var Aggregated */ protected $fileCollector; /** - * @var \Magento\Theme\Model\ResourceModel\Theme\Collection + * @var Collection */ protected $themeCollection; @@ -33,19 +46,36 @@ class Builder implements \Magento\Framework\View\Model\PageLayout\Config\Builder private $configFiles = []; /** - * @param \Magento\Framework\View\PageLayout\ConfigFactory $configFactory - * @param \Magento\Framework\View\PageLayout\File\Collector\Aggregated $fileCollector - * @param \Magento\Theme\Model\ResourceModel\Theme\Collection $themeCollection + * @var Layout|null + */ + private $cacheModel; + /** + * @var SerializerInterface|null + */ + private $serializer; + + /** + * @param ConfigFactory $configFactory + * @param Aggregated $fileCollector + * @param Collection $themeCollection + * @param Layout|null $cacheModel + * @param SerializerInterface|null $serializer */ public function __construct( - \Magento\Framework\View\PageLayout\ConfigFactory $configFactory, - \Magento\Framework\View\PageLayout\File\Collector\Aggregated $fileCollector, - \Magento\Theme\Model\ResourceModel\Theme\Collection $themeCollection + ConfigFactory $configFactory, + Aggregated $fileCollector, + Collection $themeCollection, + ?Layout $cacheModel = null, + ?SerializerInterface $serializer = null ) { $this->configFactory = $configFactory; $this->fileCollector = $fileCollector; $this->themeCollection = $themeCollection; - $this->themeCollection->setItemObjectClass(\Magento\Theme\Model\Theme\Data::class); + $this->themeCollection->setItemObjectClass(Data::class); + $this->cacheModel = $cacheModel + ?? ObjectManager::getInstance()->get(Layout::class); + $this->serializer = $serializer + ?? ObjectManager::getInstance()->get(SerializerInterface::class); } /** @@ -57,7 +87,7 @@ public function getPageLayoutsConfig() } /** - * Retrieve configuration files. + * Retrieve configuration files. Caches merged layouts.xml XML files. * * @return array */ @@ -65,10 +95,18 @@ protected function getConfigFiles() { if (!$this->configFiles) { $configFiles = []; - foreach ($this->themeCollection->loadRegisteredThemes() as $theme) { - $configFiles[] = $this->fileCollector->getFilesContent($theme, 'layouts.xml'); + $this->configFiles = $this->cacheModel->load(self::CACHE_KEY_LAYOUTS); + if (!empty($this->configFiles)) { + //if value in cache is corrupted. + $this->configFiles = $this->serializer->unserialize($this->configFiles); + } + if (empty($this->configFiles)) { + foreach ($this->themeCollection->loadRegisteredThemes() as $theme) { + $configFiles[] = $this->fileCollector->getFilesContent($theme, 'layouts.xml'); + } + $this->configFiles = array_merge(...$configFiles); + $this->cacheModel->save($this->serializer->serialize($this->configFiles), self::CACHE_KEY_LAYOUTS); } - $this->configFiles = array_merge(...$configFiles); } return $this->configFiles; diff --git a/app/code/Magento/Theme/Test/Unit/Model/PageLayout/Config/BuilderTest.php b/app/code/Magento/Theme/Test/Unit/Model/PageLayout/Config/BuilderTest.php index d9eccdb871222..2e2117b79e5ab 100644 --- a/app/code/Magento/Theme/Test/Unit/Model/PageLayout/Config/BuilderTest.php +++ b/app/code/Magento/Theme/Test/Unit/Model/PageLayout/Config/BuilderTest.php @@ -10,8 +10,11 @@ */ namespace Magento\Theme\Test\Unit\Model\PageLayout\Config; +use Magento\Framework\App\Cache\Type\Layout; +use Magento\Framework\Serialize\SerializerInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Framework\View\PageLayout\Config; +use Magento\Framework\View\PageLayout\ConfigFactory; use Magento\Framework\View\PageLayout\File\Collector\Aggregated; use Magento\Theme\Model\PageLayout\Config\Builder; use Magento\Theme\Model\ResourceModel\Theme\Collection; @@ -27,7 +30,7 @@ class BuilderTest extends TestCase protected $builder; /** - * @var \Magento\Framework\View\PageLayout\ConfigFactory|MockObject + * @var ConfigFactory|MockObject */ protected $configFactory; @@ -41,6 +44,15 @@ class BuilderTest extends TestCase */ protected $themeCollection; + /** + * @var Layout|MockObject + */ + protected $cacheModel; + /** + * @var SerializerInterface|MockObject + */ + protected $serializer; + /** * SetUp method * @@ -48,19 +60,24 @@ class BuilderTest extends TestCase */ protected function setUp(): void { - $this->configFactory = $this->getMockBuilder(\Magento\Framework\View\PageLayout\ConfigFactory::class) + $this->configFactory = $this->getMockBuilder(ConfigFactory::class) ->disableOriginalConstructor() ->setMethods(['create']) ->getMock(); - $this->fileCollector = $this->getMockBuilder( - Aggregated::class - )->disableOriginalConstructor() + $this->fileCollector = $this->getMockBuilder(Aggregated::class) + ->disableOriginalConstructor() ->getMock(); $this->themeCollection = $this->getMockBuilder(Collection::class) ->disableOriginalConstructor() ->getMock(); + $this->cacheModel = $this->getMockBuilder(Layout::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->serializer = $this->getMockForAbstractClass(SerializerInterface::class); + $this->themeCollection->expects($this->once()) ->method('setItemObjectClass') ->with(Data::class) @@ -72,7 +89,9 @@ protected function setUp(): void [ 'configFactory' => $this->configFactory, 'fileCollector' => $this->fileCollector, - 'themeCollection' => $this->themeCollection + 'themeCollection' => $this->themeCollection, + 'cacheModel' => $this->cacheModel, + 'serializer' => $this->serializer, ] ); } @@ -84,8 +103,10 @@ protected function setUp(): void */ public function testGetPageLayoutsConfig() { + $this->cacheModel->clean(); $files1 = ['content layouts_1.xml', 'content layouts_2.xml']; $files2 = ['content layouts_3.xml', 'content layouts_4.xml']; + $configFiles = array_merge($files1, $files2); $theme1 = $this->getMockBuilder(Data::class) ->disableOriginalConstructor() @@ -113,9 +134,17 @@ public function testGetPageLayoutsConfig() $this->configFactory->expects($this->once()) ->method('create') - ->with(['configFiles' => array_merge($files1, $files2)]) + ->with(['configFiles' => $configFiles]) ->willReturn($config); + $this->serializer->expects($this->once()) + ->method('serialize') + ->with($configFiles); + + $this->cacheModel->expects($this->once()) + ->method('save') + ->willReturnSelf(); + $this->assertSame($config, $this->builder->getPageLayoutsConfig()); } }