Skip to content

Commit fc025b9

Browse files
ENGCOM-7560: Introduce separate BlockByIdentifier class to get Layout Block based on CMS Block Identifier #28147
- Merge Pull Request #28147 from lbajsarowicz/magento2:feature/cms-block - Merged commits: 1. a100d24 2. 4501271 3. ae11a0c 4. 74b3e62 5. 4656d9e 6. 3e6bb4b 7. ab2be56 8. ac5ef07 9. cdcad5c 10. c3f7bed 11. 00cd00a 12. 5f3a2eb 13. 56b10a1 14. 6e2f90b 15. 476a551 16. d114bea 17. 4ad1ade 18. a851e7b
2 parents a1e5689 + a851e7b commit fc025b9

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)