Skip to content

Commit 537ced9

Browse files
Merge branch '2.4-develop' into spartans_pr_04072024
2 parents 8531110 + ada8d1d commit 537ced9

File tree

23 files changed

+678
-197
lines changed

23 files changed

+678
-197
lines changed

app/code/Magento/Catalog/view/frontend/layout/default.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
<referenceContainer name="after.body.start">
6666
<block class="Magento\Framework\View\Element\Js\Components" name="head.components" as="components" template="Magento_Catalog::js/components.phtml"/>
6767
</referenceContainer>
68+
<block class="Magento\Framework\View\Element\Template" name="head.critical" as="head.critical" template="Magento_Theme::html/container.phtml"/>
6869
<block class="Magento\Framework\View\Element\Template" name="head.additional" as="head.additional" template="Magento_Theme::html/container.phtml"/>
6970
</body>
7071
</page>

app/code/Magento/Catalog/view/frontend/web/js/product/storage/storage-service.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ define([
117117
/**
118118
* Subscribers list
119119
*/
120-
subsctibers = {};
120+
subscribers = {};
121121

122122
(function () {
123123
/**
@@ -189,12 +189,12 @@ define([
189189
* @return void
190190
*/
191191
processSubscribers: function (initialized, config) {
192-
if (subsctibers[config.namespace]) {
193-
_.each(subsctibers[config.namespace], function (callback) {
192+
if (subscribers[config.namespace]) {
193+
_.each(subscribers[config.namespace], function (callback) {
194194
callback(initialized);
195195
});
196196

197-
delete subsctibers[config.namespace];
197+
delete subscribers[config.namespace];
198198
}
199199
},
200200

@@ -209,9 +209,9 @@ define([
209209
if (storages[namespace]) {
210210
callback(storages[namespace]);
211211
} else {
212-
subsctibers[namespace] ?
213-
subsctibers[namespace].push(callback) :
214-
subsctibers[namespace] = [callback];
212+
subscribers[namespace] ?
213+
subscribers[namespace].push(callback) :
214+
subscribers[namespace] = [callback];
215215
}
216216
},
217217

app/code/Magento/Checkout/view/adminhtml/email/failed_payment.html

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,43 +23,45 @@ <h1>{{trans "Payment Transaction Failed"}}</h1>
2323

2424
<ul>
2525
<li>
26-
<strong>{{trans "Reason"}}</strong><br />
26+
<strong>{{trans "Reason"}}</strong><br>
2727
{{var reason}}
2828
</li>
2929
<li>
30-
<strong>{{trans "Checkout Type"}}</strong><br />
30+
<strong>{{trans "Checkout Type"}}</strong><br>
3131
{{var checkoutType}}
3232
</li>
3333
<li>
34-
<strong>{{trans "Customer:"}}</strong><br />
34+
<strong>{{trans "Customer:"}}</strong><br>
3535
<a href="mailto:{{var customerEmail}}">{{var customer}}</a> &lt;{{var customerEmail}}&gt;
3636
</li>
3737
<li>
38-
<strong>{{trans "Items"}}</strong><br />
38+
<strong>{{trans "Items"}}</strong><br>
3939
{{var items|raw}}
4040
</li>
4141
<li>
42-
<strong>{{trans "Total:"}}</strong><br />
42+
<strong>{{trans "Total:"}}</strong><br>
4343
{{var total}}
4444
</li>
4545
<li>
46-
<strong>{{trans "Billing Address:"}}</strong><br />
46+
<strong>{{trans "Billing Address:"}}</strong><br>
4747
{{var billingAddressHtml|raw}}
4848
</li>
49+
{{depend shippingMethod}}
4950
<li>
50-
<strong>{{trans "Shipping Address:"}}</strong><br />
51+
<strong>{{trans "Shipping Address:"}}</strong><br>
5152
{{var shippingAddressHtml|raw}}
5253
</li>
5354
<li>
54-
<strong>{{trans "Shipping Method:"}}</strong><br />
55+
<strong>{{trans "Shipping Method:"}}</strong><br>
5556
{{var shippingMethod}}
5657
</li>
58+
{{/depend}}
5759
<li>
58-
<strong>{{trans "Payment Method:"}}</strong><br />
60+
<strong>{{trans "Payment Method:"}}</strong><br>
5961
{{var paymentMethod}}
6062
</li>
6163
<li>
62-
<strong>{{trans "Date & Time:"}}</strong><br />
64+
<strong>{{trans "Date & Time:"}}</strong><br>
6365
{{var dateAndTime}}
6466
</li>
6567
</ul>
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace Magento\Cron\Cron;
11+
12+
use Magento\Config\App\Config\Type\System;
13+
use Magento\Cron\Model\DeadlockRetrierInterface;
14+
use Magento\Cron\Model\ResourceModel\Schedule;
15+
use Magento\Cron\Model\ScheduleFactory;
16+
use Magento\Cron\Observer\ProcessCronQueueObserver;
17+
use Magento\Framework\App\Config;
18+
use Magento\Framework\Stdlib\DateTime\DateTime;
19+
20+
class CleanOldJobs
21+
{
22+
/**
23+
* This docblock provides no new information
24+
*
25+
* @param Config $config
26+
* @param DateTime $dateTime
27+
* @param DeadlockRetrierInterface $retrier
28+
* @param ScheduleFactory $scheduleFactory
29+
*/
30+
public function __construct(
31+
private readonly Config $config,
32+
private readonly DateTime $dateTime,
33+
private readonly DeadlockRetrierInterface $retrier,
34+
private readonly ScheduleFactory $scheduleFactory,
35+
) {
36+
}
37+
38+
/**
39+
* Run the 'clean_cron_schedule' cronjob
40+
*
41+
* @return void
42+
*/
43+
public function execute(): void
44+
{
45+
$fullConfig = $this->config->get(System::CONFIG_TYPE);
46+
$maxLifetime = 0;
47+
48+
array_walk_recursive(
49+
$fullConfig,
50+
static function ($value, $key) use (&$maxLifetime) {
51+
if ($key === ProcessCronQueueObserver::XML_PATH_HISTORY_SUCCESS
52+
|| $key === ProcessCronQueueObserver::XML_PATH_HISTORY_FAILURE
53+
) {
54+
$maxLifetime = max($maxLifetime, (int) $value);
55+
}
56+
}
57+
);
58+
59+
if ($maxLifetime === 0) {
60+
// Something has gone wrong. Why are there no configuration values?
61+
// Drop out now to avoid doing any damage to this already-broken installation.
62+
return;
63+
}
64+
65+
// The value stored in XML is in minutes, we want seconds.
66+
$maxLifetime *= 60;
67+
68+
// Add one day to avoid removing items which are near their natural expiry anyway.
69+
$maxLifetime += 86400;
70+
71+
/** @var Schedule $scheduleResource */
72+
$scheduleResource = $this->scheduleFactory->create()->getResource();
73+
74+
$currentTime = $this->dateTime->gmtTimestamp();
75+
$deleteBefore = $scheduleResource->getConnection()->formatDate($currentTime - $maxLifetime);
76+
77+
$this->retrier->execute(
78+
function () use ($scheduleResource, $deleteBefore) {
79+
$scheduleResource->getConnection()->delete(
80+
$scheduleResource->getTable('cron_schedule'),
81+
[
82+
'scheduled_at < ?' => $deleteBefore,
83+
]
84+
);
85+
},
86+
$scheduleResource->getConnection()
87+
);
88+
}
89+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
<?php
2+
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace Magento\Cron\Test\Unit\Cron;
11+
12+
use Magento\Cron\Cron\CleanOldJobs;
13+
use Magento\Cron\Model\DeadlockRetrierInterface;
14+
use Magento\Cron\Model\ResourceModel\Schedule as ScheduleResourceModel;
15+
use Magento\Cron\Model\Schedule;
16+
use Magento\Cron\Model\ScheduleFactory;
17+
use Magento\Framework\App\Config;
18+
use Magento\Framework\DB\Adapter\AdapterInterface;
19+
use Magento\Framework\Stdlib\DateTime\DateTime;
20+
use PHPUnit\Framework\TestCase;
21+
22+
// phpcs:disable Magento2.Commenting.ClassPropertyPHPDocFormatting.Missing, because such comments would add no value.
23+
24+
class CleanOldJobsTest extends TestCase
25+
{
26+
private CleanOldJobs $cleanOldJobs;
27+
private Config $configMock;
28+
private ScheduleFactory $scheduleFactoryMock;
29+
private DateTime $dateTimeMock;
30+
private ScheduleResourceModel $scheduleResourceMock;
31+
private DeadlockRetrierInterface $retrierMock;
32+
private Schedule $scheduleMock;
33+
private int $time = 1501538400;
34+
35+
/**
36+
* @inheritdoc
37+
*/
38+
protected function setUp(): void
39+
{
40+
$this->configMock = $this->getMockBuilder(Config::class)
41+
->disableOriginalConstructor()
42+
->getMock();
43+
44+
$this->dateTimeMock = $this->getMockBuilder(DateTime::class)
45+
->disableOriginalConstructor()
46+
->getMock();
47+
$this->dateTimeMock->method('gmtTimestamp')
48+
->willReturn($this->time);
49+
50+
$this->retrierMock = $this->getMockForAbstractClass(DeadlockRetrierInterface::class);
51+
52+
$this->scheduleFactoryMock = $this->getMockBuilder(ScheduleFactory::class)
53+
->onlyMethods(['create'])
54+
->disableOriginalConstructor()
55+
->getMock();
56+
57+
$this->scheduleMock = $this->getMockBuilder(Schedule::class)
58+
->disableOriginalConstructor()
59+
->getMock();
60+
61+
$this->scheduleResourceMock = $this->getMockBuilder(ScheduleResourceModel::class)
62+
->disableOriginalConstructor()
63+
->getMock();
64+
65+
$this->scheduleMock
66+
->method('getResource')
67+
->willReturn($this->scheduleResourceMock);
68+
69+
$this->scheduleFactoryMock
70+
->method('create')
71+
->willReturn($this->scheduleMock);
72+
73+
$this->cleanOldJobs = new CleanOldJobs(
74+
$this->configMock,
75+
$this->dateTimeMock,
76+
$this->retrierMock,
77+
$this->scheduleFactoryMock
78+
);
79+
}
80+
81+
public function testSuccess(): void
82+
{
83+
$tableName = 'cron_schedule';
84+
85+
$this->configMock->expects($this->once())
86+
->method('get')
87+
->with('system')
88+
->willReturn([
89+
'history_success_lifetime' => 100,
90+
'history_failure_lifetime' => 200,
91+
]);
92+
93+
$connectionMock = $this->getMockForAbstractClass(AdapterInterface::class);
94+
95+
$connectionMock->expects($this->once())
96+
->method('delete')
97+
->with($tableName, [
98+
'scheduled_at < ?' => '$this->time - (86400 + (200 * 60))',
99+
]);
100+
101+
$connectionMock->method('formatDate')
102+
->willReturnMap([
103+
[1501538400, true, '$this->time'],
104+
[1501538200, true, '$this->time - 200'],
105+
[1501526400, true, '$this->time - (200 * 60)'],
106+
[1501452000, true, '$this->time - 86400'],
107+
[1501451800, true, '$this->time - (86400 + 200)'],
108+
[1501440000, true, '$this->time - (86400 + (200 * 60))'],
109+
]);
110+
111+
$this->scheduleResourceMock->expects($this->once())
112+
->method('getTable')
113+
->with($tableName)
114+
->willReturn($tableName);
115+
$this->scheduleResourceMock->expects($this->exactly(3))
116+
->method('getConnection')
117+
->willReturn($connectionMock);
118+
119+
$this->retrierMock->expects($this->once())
120+
->method('execute')
121+
->willReturnCallback(
122+
function ($callback) {
123+
return $callback();
124+
}
125+
);
126+
127+
$this->cleanOldJobs->execute();
128+
}
129+
130+
public function testNoActionWhenEmptyConfig(): void
131+
{
132+
$this->configMock->expects($this->once())
133+
->method('get')
134+
->with('system')
135+
->willReturn([]);
136+
137+
$this->scheduleFactoryMock->expects($this->never())->method('create');
138+
139+
$this->cleanOldJobs->execute();
140+
}
141+
}

app/code/Magento/Cron/composer.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@
77
"require": {
88
"php": "~8.1.0||~8.2.0||~8.3.0",
99
"magento/framework": "*",
10+
"magento/module-config": "^100.1.2 || ^101.0",
1011
"magento/module-store": "*"
1112
},
12-
"suggest": {
13-
"magento/module-config": "*"
14-
},
1513
"type": "magento2-module",
1614
"license": [
1715
"OSL-3.0",

app/code/Magento/Cron/etc/crontab.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
9+
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/crontab.xsd">
10+
<group id="default">
11+
<job name="clean_cron_schedule"
12+
instance="Magento\Cron\Cron\CleanOldJobs"
13+
method="execute">
14+
<schedule>0 0 * * *</schedule>
15+
</job>
16+
</group>
17+
</config>

app/code/Magento/Cron/etc/module.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
99
<module name="Magento_Cron" >
1010
<sequence>
11+
<module name="Magento_Config"/>
1112
<module name="Magento_Store"/>
1213
</sequence>
1314
</module>

app/code/Magento/Eav/etc/db_schema.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,10 @@
463463
<constraint xsi:type="foreign" referenceId="EAV_ATTRIBUTE_OPTION_VALUE_STORE_ID_STORE_STORE_ID"
464464
table="eav_attribute_option_value" column="store_id" referenceTable="store"
465465
referenceColumn="store_id" onDelete="CASCADE"/>
466+
<constraint xsi:type="unique" referenceId="EAV_ATTRIBUTE_OPTION_VALUE_STORE_ID_OPTION_ID">
467+
<column name="store_id"/>
468+
<column name="option_id"/>
469+
</constraint>
466470
<index referenceId="EAV_ATTRIBUTE_OPTION_VALUE_OPTION_ID" indexType="btree">
467471
<column name="option_id"/>
468472
</index>

app/code/Magento/Eav/etc/db_schema_whitelist.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,8 @@
290290
"constraint": {
291291
"PRIMARY": true,
292292
"EAV_ATTR_OPT_VAL_OPT_ID_EAV_ATTR_OPT_OPT_ID": true,
293-
"EAV_ATTRIBUTE_OPTION_VALUE_STORE_ID_STORE_STORE_ID": true
293+
"EAV_ATTRIBUTE_OPTION_VALUE_STORE_ID_STORE_STORE_ID": true,
294+
"EAV_ATTRIBUTE_OPTION_VALUE_STORE_ID_OPTION_ID": true
294295
}
295296
},
296297
"eav_attribute_label": {

0 commit comments

Comments
 (0)