Skip to content

Commit bf79b4a

Browse files
committed
Merge remote-tracking branch 'origin/AC-14567-v1' into spartans_pr_05062025
2 parents 7da46f5 + 60970f7 commit bf79b4a

File tree

2 files changed

+244
-3
lines changed

2 files changed

+244
-3
lines changed
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All rights reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Framework\Mview\View;
9+
10+
use Magento\Framework\App\ResourceConnection;
11+
use Magento\Framework\DB\Ddl\Trigger;
12+
use Magento\Framework\DB\Ddl\TriggerFactory;
13+
use Magento\Framework\Mview\Config;
14+
use Magento\Framework\Mview\View\CollectionInterface;
15+
use Magento\Framework\Mview\View\Subscription;
16+
use Magento\Framework\Mview\View\SubscriptionStatementPostprocessorInterface;
17+
use Magento\Framework\Mview\ViewInterface;
18+
use Magento\TestFramework\Helper\Bootstrap;
19+
use PHPUnit\Framework\TestCase;
20+
21+
/**
22+
* Integration test for \Magento\Framework\Mview\View\Subscription
23+
*
24+
* @magentoDbIsolation disabled
25+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
26+
*/
27+
class SubscriptionTest extends TestCase
28+
{
29+
/**
30+
* @var Subscription
31+
*/
32+
private $subscription;
33+
34+
/**
35+
* @var ResourceConnection
36+
*/
37+
private $resource;
38+
39+
/**
40+
* @var TriggerFactory
41+
*/
42+
private $triggerFactory;
43+
44+
/**
45+
* @var CollectionInterface
46+
*/
47+
private $viewCollection;
48+
49+
/**
50+
* @var ViewInterface
51+
*/
52+
private $view;
53+
54+
/**
55+
* @var Config
56+
*/
57+
private $mviewConfig;
58+
59+
/**
60+
* @var SubscriptionStatementPostprocessorInterface
61+
*/
62+
private $statementPostprocessor;
63+
64+
/**
65+
* @inheritdoc
66+
*/
67+
protected function setUp(): void
68+
{
69+
$objectManager = Bootstrap::getObjectManager();
70+
$this->resource = $objectManager->get(ResourceConnection::class);
71+
$this->triggerFactory = $objectManager->get(TriggerFactory::class);
72+
$this->viewCollection = $objectManager->get(CollectionInterface::class);
73+
$this->mviewConfig = $objectManager->get(Config::class);
74+
$this->statementPostprocessor = $objectManager->get(SubscriptionStatementPostprocessorInterface::class);
75+
76+
// Create a test view
77+
$this->view = $objectManager->create(ViewInterface::class);
78+
$this->view->setId('test_view')
79+
->setData('subscriptions', [
80+
'catalog_product_entity' => [
81+
'name' => 'catalog_product_entity',
82+
'column' => 'entity_id',
83+
'subscription_model' => null,
84+
'processor' => \Magento\Framework\Mview\View\AdditionalColumnsProcessor\DefaultProcessor::class
85+
]
86+
]);
87+
88+
// Create changelog for the view
89+
$changelog = $objectManager->create(\Magento\Framework\Mview\View\Changelog::class);
90+
$changelog->setViewId('test_view');
91+
$changelog->create();
92+
93+
// Set up view state
94+
$state = $objectManager->create(\Magento\Framework\Mview\View\StateInterface::class);
95+
$state->setViewId('test_view')
96+
->setMode(\Magento\Framework\Mview\View\StateInterface::MODE_ENABLED)
97+
->setStatus(\Magento\Framework\Mview\View\StateInterface::STATUS_IDLE)
98+
->save();
99+
100+
$this->view->setState($state);
101+
102+
// Configure the view in Mview configuration
103+
$configData = $objectManager->get(\Magento\Framework\Mview\Config\Data::class);
104+
$configData->merge([
105+
'test_view' => [
106+
'view_id' => 'test_view',
107+
'action_class' => \Magento\Framework\Indexer\Action\Dummy::class,
108+
'group' => 'indexer',
109+
'subscriptions' => [
110+
'catalog_product_entity' => [
111+
'name' => 'catalog_product_entity',
112+
'column' => 'entity_id',
113+
'subscription_model' => null,
114+
'processor' => \Magento\Framework\Mview\View\AdditionalColumnsProcessor\DefaultProcessor::class
115+
]
116+
]
117+
]
118+
]);
119+
120+
$this->subscription = new Subscription(
121+
$this->resource,
122+
$this->triggerFactory,
123+
$this->viewCollection,
124+
$this->view,
125+
'catalog_product_entity',
126+
'entity_id',
127+
['updated_at'],
128+
[],
129+
$this->mviewConfig,
130+
$this->statementPostprocessor
131+
);
132+
}
133+
134+
/**
135+
* @inheritdoc
136+
*/
137+
protected function tearDown(): void
138+
{
139+
// Clean up changelog table
140+
$changelog = $this->view->getChangelog();
141+
if ($changelog) {
142+
$changelog->drop();
143+
}
144+
145+
// Clean up state
146+
$state = $this->view->getState();
147+
if ($state) {
148+
$state->delete();
149+
}
150+
}
151+
152+
/**
153+
* Test creating database triggers
154+
*/
155+
public function testCreateTriggers(): void
156+
{
157+
// Create triggers
158+
$this->subscription->create();
159+
160+
// Verify triggers were created
161+
$connection = $this->resource->getConnection();
162+
$triggers = $this->subscription->getTriggers();
163+
164+
foreach ($triggers as $trigger) {
165+
$triggerName = $trigger->getName();
166+
$result = $connection->fetchOne(
167+
"SELECT TRIGGER_NAME FROM information_schema.TRIGGERS WHERE TRIGGER_NAME = ?",
168+
[$triggerName]
169+
);
170+
$this->assertNotEmpty(
171+
$result,
172+
sprintf('Trigger %s was not created', $triggerName)
173+
);
174+
}
175+
}
176+
177+
/**
178+
* Test removing database triggers
179+
*/
180+
public function testRemoveTriggers(): void
181+
{
182+
// First create triggers
183+
$this->subscription->create();
184+
185+
// Get trigger names before removal
186+
$triggers = $this->subscription->getTriggers();
187+
$triggerNames = array_map(function ($trigger) {
188+
return $trigger->getName();
189+
}, $triggers);
190+
191+
// Remove triggers
192+
$this->subscription->remove();
193+
194+
// Verify triggers were removed
195+
$connection = $this->resource->getConnection();
196+
foreach ($triggerNames as $triggerName) {
197+
$this->assertFalse(
198+
$connection->isTableExists($triggerName),
199+
sprintf('Trigger %s was not removed', $triggerName)
200+
);
201+
}
202+
}
203+
204+
/**
205+
* Test trigger statements for ignored columns
206+
*/
207+
public function testTriggerStatementsWithIgnoredColumns(): void
208+
{
209+
$this->subscription->create();
210+
$triggers = $this->subscription->getTriggers();
211+
212+
// Find the UPDATE trigger
213+
$updateTrigger = null;
214+
foreach ($triggers as $trigger) {
215+
if ($trigger->getEvent() === Trigger::EVENT_UPDATE) {
216+
$updateTrigger = $trigger;
217+
break;
218+
}
219+
}
220+
221+
$this->assertNotNull($updateTrigger, 'UPDATE trigger not found');
222+
223+
// Verify the trigger statements contain the ignored column check
224+
$statements = $updateTrigger->getStatements();
225+
$this->assertNotEmpty($statements, 'Trigger has no statements');
226+
227+
// Check that updated_at is NOT in the list of columns being checked
228+
$hasIgnoredColumnCheck = true;
229+
foreach ($statements as $statement) {
230+
if (strpos($statement, 'NOT(NEW.`updated_at` <=> OLD.`updated_at`)') !== false) {
231+
$hasIgnoredColumnCheck = false;
232+
break;
233+
}
234+
}
235+
236+
$this->assertTrue(
237+
$hasIgnoredColumnCheck,
238+
'Trigger contains check for ignored column'
239+
);
240+
}
241+
}

lib/internal/Magento/Framework/Mview/View/Subscription.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2014 Adobe
4+
* All rights reserved.
55
*/
66

77
namespace Magento\Framework\Mview\View;
@@ -297,7 +297,7 @@ protected function prepareColumns(ViewInterface $view, string $event): array
297297
*/
298298
protected function buildStatement(string $event, ViewInterface $view): string
299299
{
300-
$trigger = "%sINSERT IGNORE INTO %s (%s) VALUES (%s);";
300+
$trigger = "%sINSERT INTO %s (%s) VALUES (%s);";
301301
$changelog = $view->getChangelog();
302302

303303
switch ($event) {

0 commit comments

Comments
 (0)