Skip to content

Commit cb916a3

Browse files
authored
ENGCOM-7560: Introduce separate BlockByIdentifier class to get Layout Block based on CMS Block Identifier #28147
2 parents a114caa + fc025b9 commit cb916a3

File tree

3 files changed

+402
-0
lines changed

3 files changed

+402
-0
lines changed

app/code/Magento/Cms/Block/Block.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
/**
1212
* Cms block content block
13+
* @deprecated This class introduces caching issues and should no longer be used
14+
* @see \Magento\Cms\Block\BlockByIdentifier
1315
*/
1416
class Block extends AbstractBlock implements \Magento\Framework\DataObject\IdentityInterface
1517
{
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Cms\Block;
9+
10+
use Magento\Cms\Api\Data\BlockInterface;
11+
use Magento\Cms\Api\GetBlockByIdentifierInterface;
12+
use Magento\Cms\Model\Block as BlockModel;
13+
use Magento\Cms\Model\Template\FilterProvider;
14+
use Magento\Framework\DataObject\IdentityInterface;
15+
use Magento\Framework\Exception\NoSuchEntityException;
16+
use Magento\Framework\View\Element\AbstractBlock;
17+
use Magento\Framework\View\Element\Context;
18+
use Magento\Store\Model\StoreManagerInterface;
19+
20+
/**
21+
* This class is replacement of \Magento\Cms\Block\Block, that accepts only `string` identifier of CMS Block
22+
*/
23+
class BlockByIdentifier extends AbstractBlock implements IdentityInterface
24+
{
25+
public const CACHE_KEY_PREFIX = 'CMS_BLOCK';
26+
27+
/**
28+
* @var GetBlockByIdentifierInterface
29+
*/
30+
private $blockByIdentifier;
31+
32+
/**
33+
* @var StoreManagerInterface
34+
*/
35+
private $storeManager;
36+
37+
/**
38+
* @var FilterProvider
39+
*/
40+
private $filterProvider;
41+
42+
/**
43+
* @var BlockInterface
44+
*/
45+
private $cmsBlock;
46+
47+
/**
48+
* @param GetBlockByIdentifierInterface $blockByIdentifier
49+
* @param StoreManagerInterface $storeManager
50+
* @param FilterProvider $filterProvider
51+
* @param Context $context
52+
* @param array $data
53+
*/
54+
public function __construct(
55+
GetBlockByIdentifierInterface $blockByIdentifier,
56+
StoreManagerInterface $storeManager,
57+
FilterProvider $filterProvider,
58+
Context $context,
59+
array $data = []
60+
) {
61+
parent::__construct($context, $data);
62+
$this->blockByIdentifier = $blockByIdentifier;
63+
$this->storeManager = $storeManager;
64+
$this->filterProvider = $filterProvider;
65+
}
66+
67+
/**
68+
* @inheritDoc
69+
*/
70+
protected function _toHtml(): string
71+
{
72+
try {
73+
return $this->filterOutput(
74+
$this->getCmsBlock()->getContent()
75+
);
76+
} catch (NoSuchEntityException $e) {
77+
return '';
78+
}
79+
}
80+
81+
/**
82+
* Returns the value of `identifier` injected in `<block>` definition
83+
*
84+
* @return string|null
85+
*/
86+
private function getIdentifier(): ?string
87+
{
88+
return $this->getData('identifier') ?: null;
89+
}
90+
91+
/**
92+
* Filters the Content
93+
*
94+
* @param string $content
95+
* @return string
96+
* @throws NoSuchEntityException
97+
*/
98+
private function filterOutput(string $content): string
99+
{
100+
return $this->filterProvider->getBlockFilter()
101+
->setStoreId($this->getCurrentStoreId())
102+
->filter($content);
103+
}
104+
105+
/**
106+
* Loads the CMS block by `identifier` provided as an argument
107+
*
108+
* @return BlockInterface|BlockModel
109+
* @throws \InvalidArgumentException
110+
* @throws NoSuchEntityException
111+
*/
112+
private function getCmsBlock(): BlockInterface
113+
{
114+
if (!$this->getIdentifier()) {
115+
throw new \InvalidArgumentException('Expected value of `identifier` was not provided');
116+
}
117+
118+
if (null === $this->cmsBlock) {
119+
$this->cmsBlock = $this->blockByIdentifier->execute(
120+
(string)$this->getIdentifier(),
121+
$this->getCurrentStoreId()
122+
);
123+
124+
if (!$this->cmsBlock->isActive()) {
125+
throw new NoSuchEntityException(
126+
__('The CMS block with identifier "%identifier" is not enabled.', $this->getIdentifier())
127+
);
128+
}
129+
}
130+
131+
return $this->cmsBlock;
132+
}
133+
134+
/**
135+
* Returns the current Store ID
136+
*
137+
* @return int
138+
* @throws \Magento\Framework\Exception\NoSuchEntityException
139+
*/
140+
private function getCurrentStoreId(): int
141+
{
142+
return (int)$this->storeManager->getStore()->getId();
143+
}
144+
145+
/**
146+
* Returns array of Block Identifiers used to determine Cache Tags
147+
*
148+
* This implementation supports different CMS blocks caching having the same identifier,
149+
* resolving the bug introduced in scope of \Magento\Cms\Block\Block
150+
*
151+
* @return string[]
152+
*/
153+
public function getIdentities(): array
154+
{
155+
if (!$this->getIdentifier()) {
156+
return [];
157+
}
158+
159+
$identities = [
160+
self::CACHE_KEY_PREFIX . '_' . $this->getIdentifier(),
161+
self::CACHE_KEY_PREFIX . '_' . $this->getIdentifier() . '_' . $this->getCurrentStoreId()
162+
];
163+
164+
try {
165+
$cmsBlock = $this->getCmsBlock();
166+
if ($cmsBlock instanceof IdentityInterface) {
167+
$identities = array_merge($identities, $cmsBlock->getIdentities());
168+
}
169+
// phpcs:ignore Magento2.CodeAnalysis.EmptyBlock.DetectedCatch
170+
} catch (NoSuchEntityException $e) {
171+
}
172+
173+
return $identities;
174+
}
175+
}

0 commit comments

Comments
 (0)