Skip to content

Commit cfe41e5

Browse files
authored
Merge branch '2.4-develop' into ds_fix-docs
2 parents 0630664 + 6f5a25e commit cfe41e5

File tree

3 files changed

+213
-3
lines changed

3 files changed

+213
-3
lines changed

lib/internal/Magento/Framework/App/Cache/Type/Layout.php

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,39 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
declare(strict_types=1);
7+
68
namespace Magento\Framework\App\Cache\Type;
79

810
/**
911
* System / Cache Management / Cache type "Layouts"
1012
*/
1113
class Layout extends \Magento\Framework\Cache\Frontend\Decorator\TagScope
1214
{
15+
/**
16+
* Prefix for hash kay and hash data
17+
*/
18+
public const HASH_PREFIX = 'l:';
19+
20+
/**
21+
* Hash type, not used for security, only for uniqueness
22+
*/
23+
public const HASH_TYPE = 'xxh3';
24+
25+
/**
26+
* Data lifetime in milliseconds
27+
*/
28+
public const DATA_LIFETIME = 86_400_000; // "1 day" milliseconds
29+
1330
/**
1431
* Cache type code unique among all cache types
1532
*/
16-
const TYPE_IDENTIFIER = 'layout';
33+
public const TYPE_IDENTIFIER = 'layout';
1734

1835
/**
1936
* Cache tag used to distinguish the cache type from all other cache
2037
*/
21-
const CACHE_TAG = 'LAYOUT_GENERAL_CACHE_TAG';
38+
public const CACHE_TAG = 'LAYOUT_GENERAL_CACHE_TAG';
2239

2340
/**
2441
* @param FrontendPool $cacheFrontendPool
@@ -27,4 +44,33 @@ public function __construct(FrontendPool $cacheFrontendPool)
2744
{
2845
parent::__construct($cacheFrontendPool->get(self::TYPE_IDENTIFIER), self::CACHE_TAG);
2946
}
47+
48+
/**
49+
* @inheritDoc
50+
*/
51+
public function save($data, $identifier, array $tags = [], $lifeTime = null)
52+
{
53+
$dataHash = hash(self::HASH_TYPE, $data);
54+
$identifierForHash = self::HASH_PREFIX . $dataHash;
55+
return parent::save($data, $identifierForHash, $tags, self::DATA_LIFETIME) // key is hash of data hash
56+
&& parent::save(self::HASH_PREFIX . $dataHash, $identifier, $tags, $lifeTime); // store hash of data
57+
}
58+
59+
/**
60+
* @inheritDoc
61+
*/
62+
public function load($identifier)
63+
{
64+
$data = parent::load($identifier);
65+
if ($data === false || $data === null) {
66+
return $data;
67+
}
68+
69+
if (str_starts_with($data, self::HASH_PREFIX)) {
70+
// so data stored in other place
71+
return parent::load($data);
72+
} else {
73+
return $data;
74+
}
75+
}
3076
}
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
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\Framework\App\Test\Unit\Cache;
9+
10+
use Magento\Framework\App\Cache\Type\FrontendPool;
11+
use Magento\Framework\App\Cache\Type\Layout;
12+
use Magento\Framework\Cache\FrontendInterface;
13+
use PHPUnit\Framework\MockObject\MockObject;
14+
use PHPUnit\Framework\TestCase;
15+
16+
class LayoutTest extends TestCase
17+
{
18+
/**
19+
* @var FrontendInterface|MockObject
20+
*/
21+
private $cacheFrontendMock;
22+
23+
/**
24+
* @var Layout
25+
*/
26+
private $layoutCacheType;
27+
28+
protected function setUp(): void
29+
{
30+
$this->cacheFrontendMock = $this->createMock(FrontendInterface::class);
31+
$frontendPoolMock = $this->createMock(FrontendPool::class);
32+
$frontendPoolMock->method('get')
33+
->with(Layout::TYPE_IDENTIFIER)
34+
->willReturn($this->cacheFrontendMock);
35+
36+
$this->layoutCacheType = new Layout($frontendPoolMock);
37+
}
38+
39+
/**
40+
* @param string $data
41+
* @param string $identifier
42+
* @return void
43+
* @dataProvider dataProviderForSaveDataTest
44+
*/
45+
public function testSaveData(string $data, string $identifier)
46+
{
47+
$tags = ['tag1', 'tag2'];
48+
$lifeTime = 1000;
49+
50+
$dataHash = hash(Layout::HASH_TYPE, $data);
51+
$identifierForHash = Layout::HASH_PREFIX . $dataHash;
52+
53+
$expectedTags = array_merge($tags, [Layout::CACHE_TAG]);
54+
$invocation = 0;
55+
56+
$this->cacheFrontendMock->method('save')
57+
->willReturnCallback(
58+
function (
59+
$passedData,
60+
$passedIdentifier,
61+
$passedTags,
62+
$passedLifeTime
63+
) use (
64+
&$invocation,
65+
$data,
66+
$identifierForHash,
67+
$expectedTags,
68+
$lifeTime,
69+
$identifier
70+
) {
71+
if ($invocation === 0) {
72+
$this->assertEquals($data, $passedData);
73+
$this->assertEquals($identifierForHash, $passedIdentifier);
74+
$this->assertEquals($expectedTags, $passedTags);
75+
$this->assertEquals(Layout::DATA_LIFETIME, $passedLifeTime);
76+
} elseif ($invocation === 1) {
77+
$this->assertEquals($identifierForHash, $passedData);
78+
$this->assertEquals($identifier, $passedIdentifier);
79+
$this->assertEquals($expectedTags, $passedTags);
80+
$this->assertEquals($lifeTime, $passedLifeTime);
81+
}
82+
$invocation++;
83+
return true;
84+
}
85+
);
86+
87+
$result = $this->layoutCacheType->save($data, $identifier, $tags, $lifeTime);
88+
$this->assertTrue($result);
89+
}
90+
91+
/**
92+
* Data provider for the testSaveData test.
93+
*/
94+
public function dataProviderForSaveDataTest(): array
95+
{
96+
return [
97+
'Test with normal data' => ['test-data', 'test-identifier'],
98+
'Test with empty string' => ['', 'empty-string-identifier'],
99+
];
100+
}
101+
102+
/**
103+
* @param string $identifier
104+
* @param bool|string|null $firstLoadReturn
105+
* @param string|null $secondLoadReturn
106+
* @param bool|string|null $expectedResult
107+
* @return void
108+
* @dataProvider loadDataProvider
109+
*/
110+
public function testLoadData(
111+
string $identifier,
112+
bool|string|null $firstLoadReturn,
113+
?string $secondLoadReturn,
114+
bool|string|null $expectedResult
115+
) {
116+
$this->cacheFrontendMock->method('load')
117+
->willReturnMap([
118+
[$identifier, $firstLoadReturn],
119+
[$firstLoadReturn, $secondLoadReturn]
120+
]);
121+
122+
$result = $this->layoutCacheType->load($identifier);
123+
$this->assertEquals($expectedResult, $result);
124+
}
125+
126+
public function loadDataProvider(): array
127+
{
128+
$identifier = 'test-identifier';
129+
$hashedValue = Layout::HASH_PREFIX . hash(Layout::HASH_TYPE, 'test-data');
130+
$rawData = 'raw-test-data';
131+
$nonExistentIdentifier = 'non-existent-identifier';
132+
133+
return [
134+
// Test with hash prefix and successful nested load
135+
[
136+
'identifier' => $identifier,
137+
'firstLoadReturn' => $hashedValue,
138+
'secondLoadReturn' => 'test-data',
139+
'expectedResult' => 'test-data',
140+
],
141+
// Test when identifier does not exist
142+
[
143+
'identifier' => $nonExistentIdentifier,
144+
'firstLoadReturn' => false,
145+
'secondLoadReturn' => null, // Not used, since first load returns false
146+
'expectedResult' => false,
147+
],
148+
// Test with null value, assuming null is an acceptable return value
149+
[
150+
'identifier' => $nonExistentIdentifier,
151+
'firstLoadReturn' => null,
152+
'secondLoadReturn' => null, // Not used, since first load returns null
153+
'expectedResult' => null,
154+
],
155+
// Test without hash prefix
156+
[
157+
'identifier' => $identifier,
158+
'firstLoadReturn' => $rawData,
159+
'secondLoadReturn' => null, // Not used, since no hash prefix is present
160+
'expectedResult' => $rawData,
161+
],
162+
];
163+
}
164+
}

lib/internal/Magento/Framework/Cache/Backend/Redis.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public function load($id, $doNotTestCacheValidity = false)
7070
* @param bool $specificLifetime
7171
* @return bool
7272
*/
73-
public function save($data, $id, $tags = [], $specificLifetime = false)
73+
public function save($data, $id, $tags = [], $specificLifetime = 86_400_000)
7474
{
7575
// @todo add special handling of MAGE tag, save clenup
7676
try {

0 commit comments

Comments
 (0)