Skip to content

Commit ec524e4

Browse files
authored
Merge pull request #6 from magento-commerce/imported-magento-magento-semver-54
[Imported] Svc checker for et_schema.xml files
2 parents 9ef0241 + 68b83ca commit ec524e4

12 files changed

+667
-3
lines changed

src/Analyzer/EtSchemaAnalyzer.php

Lines changed: 367 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
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\SemanticVersionChecker\Analyzer;
11+
12+
use PhpParser\Node\Stmt;
13+
use PHPSemVerChecker\Registry\Registry;
14+
use PHPSemVerChecker\Report\Report;
15+
use PHPSemVerChecker\SemanticVersioning\Level;
16+
use Magento\SemanticVersionChecker\Operation\EtSchema\EtSchemaOperation;
17+
18+
/**
19+
* Class EtSchemaAnalyzer analyzes changes in et_schema.xml
20+
*/
21+
class EtSchemaAnalyzer implements AnalyzerInterface
22+
{
23+
24+
/**
25+
* Analyser context
26+
*/
27+
public const CONTEXT = 'etSchema';
28+
29+
/**
30+
* @var array of actions
31+
*/
32+
private static $actions = [
33+
'addedRecord' => [
34+
'level' => Level::MINOR,
35+
'code' => 'T004',
36+
'message' => 'Added a new declaration for record %s.'
37+
],
38+
'removedRecord' => [
39+
'level' => Level::MAJOR,
40+
'code' => 'T001',
41+
'message' => 'Removed declaration for type %s.'
42+
],
43+
'addedField' => [
44+
'level' => Level::PATCH,
45+
'code' => 'T005',
46+
'message' => 'Added field %s to type %s.'
47+
],
48+
'removedField' => [
49+
'level' => Level::MAJOR,
50+
'code' => 'T002',
51+
'message' => 'Removed field %s from type %s.'
52+
],
53+
'changedField' => [
54+
'level' => Level::MAJOR,
55+
'code' => 'T003',
56+
'message' => 'Changed field %s declaration in type %s.'
57+
]
58+
];
59+
60+
/**
61+
* @var Report
62+
*/
63+
private $report;
64+
65+
/**
66+
* Constructor.
67+
*
68+
* @param Report $report
69+
*/
70+
public function __construct(Report $report)
71+
{
72+
$this->report = $report;
73+
}
74+
75+
/**
76+
* Process a new configuration file
77+
*
78+
* @param array $moduleConfig
79+
* @return array
80+
*/
81+
private function addedModuleConfig(array $moduleConfig): array
82+
{
83+
$changes = [];
84+
foreach ($moduleConfig as $moduleName => $records) {
85+
foreach ($records as $record) {
86+
$changes[] = $this->addedRecord($moduleName, $record['name']);
87+
}
88+
}
89+
return $changes;
90+
}
91+
92+
/**
93+
* Process removed configuration file
94+
*
95+
* @param array $moduleConfig
96+
* @return array
97+
*/
98+
private function removedModuleConfig(array $moduleConfig): array
99+
{
100+
$changes = [];
101+
foreach ($moduleConfig as $moduleName => $records) {
102+
foreach ($records as $record) {
103+
$changes[] = $this->removedRecord($moduleName, $record['name']);
104+
}
105+
}
106+
return $changes;
107+
}
108+
109+
/**
110+
* Register record creation
111+
*
112+
* @param string $moduleName
113+
* @param string $recordName
114+
* @return array
115+
*/
116+
private function addedRecord(string $moduleName, string $recordName): array
117+
{
118+
return [
119+
'level' => self::$actions[__FUNCTION__]['level'],
120+
'code' => self::$actions[__FUNCTION__]['code'],
121+
'location' => sprintf('urn:magento:module:%s:etc/et_schema.xml %s', $moduleName, $recordName),
122+
'target' => $recordName,
123+
'reason' => sprintf(self::$actions[__FUNCTION__]['message'], $recordName)
124+
];
125+
}
126+
127+
/**
128+
* Register record removal
129+
*
130+
* @param string $moduleName
131+
* @param string $recordName
132+
* @return array
133+
*/
134+
private function removedRecord(string $moduleName, string $recordName): array
135+
{
136+
return [
137+
'level' => self::$actions[__FUNCTION__]['level'],
138+
'code' => self::$actions[__FUNCTION__]['code'],
139+
'location' => sprintf('urn:magento:module:%s:etc/et_schema.xml %s', $moduleName, $recordName),
140+
'target' => $recordName,
141+
'reason' => sprintf(self::$actions[__FUNCTION__]['message'], $recordName)
142+
];
143+
}
144+
145+
/**
146+
* Register removed field
147+
*
148+
* @param string $moduleName
149+
* @param string $recordName
150+
* @param string $fieldName
151+
* @return array
152+
*/
153+
private function removedField(string $moduleName, string $recordName, string $fieldName): array
154+
{
155+
return [
156+
'level' => self::$actions[__FUNCTION__]['level'],
157+
'code' => self::$actions[__FUNCTION__]['code'],
158+
'location' => sprintf(
159+
'urn:magento:module:%s:etc/et_schema.xml %s:%s',
160+
$moduleName,
161+
$recordName,
162+
$fieldName
163+
),
164+
'target' => $recordName,
165+
'reason' => sprintf(self::$actions[__FUNCTION__]['message'], $fieldName, $recordName)
166+
];
167+
}
168+
169+
/**
170+
* Register a new field
171+
*
172+
* @param string $moduleName
173+
* @param string $recordName
174+
* @param string $fieldName
175+
* @return array
176+
*/
177+
private function addedField(string $moduleName, string $recordName, string $fieldName): array
178+
{
179+
return [
180+
'level' => self::$actions[__FUNCTION__]['level'],
181+
'code' => self::$actions[__FUNCTION__]['code'],
182+
'location' => sprintf(
183+
'urn:magento:module:%s:etc/et_schema.xml %s:%s',
184+
$moduleName,
185+
$recordName,
186+
$fieldName
187+
),
188+
'target' => $recordName,
189+
'reason' => sprintf(self::$actions[__FUNCTION__]['message'], $fieldName, $recordName)
190+
];
191+
}
192+
193+
/**
194+
* Register field change
195+
*
196+
* @param string $moduleName
197+
* @param string $recordName
198+
* @param string $fieldName
199+
* @return array
200+
*/
201+
private function changedField(string $moduleName, string $recordName, string $fieldName): array
202+
{
203+
return [
204+
'level' => self::$actions[__FUNCTION__]['level'],
205+
'code' => self::$actions[__FUNCTION__]['code'],
206+
'location' => sprintf(
207+
'urn:magento:module:%s:etc/et_schema.xml %s:%s',
208+
$moduleName,
209+
$recordName,
210+
$fieldName
211+
),
212+
'target' => $recordName,
213+
'reason' => sprintf(self::$actions[__FUNCTION__]['message'], $fieldName, $recordName)
214+
];
215+
}
216+
217+
/**
218+
* Analyze record structure
219+
*
220+
* @param string $moduleName
221+
* @param $beforeRecord
222+
* @param $afterRecord
223+
* @return array
224+
*/
225+
private function analyzeRecord(string $moduleName, array $beforeRecord, array $afterRecord): array
226+
{
227+
$changes = [];
228+
$commonFields = array_intersect(
229+
array_keys($beforeRecord['field']),
230+
array_keys($afterRecord['field'])
231+
);
232+
foreach ($commonFields as $fieldName) {
233+
if (
234+
$beforeRecord['field'][$fieldName]['type'] !== $afterRecord['field'][$fieldName]['type']
235+
|| $beforeRecord['field'][$fieldName]['repeated'] !== $afterRecord['field'][$fieldName]['repeated']
236+
) {
237+
$changes[] = $this->changedField($moduleName, $beforeRecord['name'], $fieldName);
238+
}
239+
}
240+
$diff = array_merge(
241+
array_diff(
242+
array_keys($beforeRecord['field']),
243+
array_keys($afterRecord['field'])
244+
),
245+
array_diff(
246+
array_keys($afterRecord['field']),
247+
array_keys($beforeRecord['field'])
248+
)
249+
);
250+
foreach ($diff as $fieldName) {
251+
if (isset($beforeRecord['field'][$fieldName])) {
252+
$changes[] = $this->removedField($moduleName, $beforeRecord['name'], $fieldName);
253+
} else {
254+
$changes[] = $this->addedField($moduleName, $afterRecord['name'], $fieldName);
255+
}
256+
}
257+
return $changes;
258+
}
259+
260+
/**
261+
* Analyze module configuration file
262+
*
263+
* @param string $moduleName
264+
* @param array $beforeModuleConfig
265+
* @param array $afterModuleConfig
266+
* @return array
267+
*/
268+
private function analyzeModuleConfig(string $moduleName, array $beforeModuleConfig, array $afterModuleConfig): array
269+
{
270+
$changes = [];
271+
$commonRecords = array_intersect(
272+
array_keys($beforeModuleConfig),
273+
array_keys($afterModuleConfig)
274+
);
275+
foreach ($commonRecords as $recordName) {
276+
$changes = array_merge(
277+
$changes,
278+
$this->analyzeRecord(
279+
$moduleName,
280+
$beforeModuleConfig[$recordName],
281+
$afterModuleConfig[$recordName]
282+
)
283+
);
284+
}
285+
$diff = array_merge(
286+
array_diff(
287+
array_keys($beforeModuleConfig),
288+
array_keys($afterModuleConfig)
289+
),
290+
array_diff(
291+
array_keys($afterModuleConfig),
292+
array_keys($beforeModuleConfig)
293+
)
294+
);
295+
foreach ($diff as $recordName) {
296+
if (isset($beforeModuleConfig[$recordName])) {
297+
$changes[] = $this->removedRecord($moduleName, $recordName);
298+
} else {
299+
$changes[] = $this->addedRecord($moduleName, $recordName);
300+
}
301+
}
302+
return $changes;
303+
}
304+
305+
/**
306+
* Register changes to the report
307+
*
308+
* @param array $changes
309+
*/
310+
public function reportChanges(array $changes): void
311+
{
312+
foreach ($changes as $change) {
313+
$this->report->add(
314+
self::CONTEXT,
315+
new EtSchemaOperation(
316+
$change['location'],
317+
$change['code'],
318+
$change['target'],
319+
$change['reason'],
320+
$change['level']
321+
)
322+
);
323+
}
324+
}
325+
326+
/**
327+
* Analyze configuration changes
328+
*
329+
* @param Stmt|Registry $registryBefore
330+
* @param Stmt|Registry $registryAfter
331+
* @return Report
332+
*/
333+
public function analyze($registryBefore, $registryAfter)
334+
{
335+
$before = isset($registryBefore->data[self::CONTEXT]) ? $registryBefore->data[self::CONTEXT] : [];
336+
$after = isset($registryAfter->data[self::CONTEXT]) ? $registryAfter->data[self::CONTEXT] : [];
337+
$changes = [];
338+
$commonModules = array_intersect(array_keys($before), array_keys($after));
339+
foreach ($commonModules as $moduleName) {
340+
$changes = array_merge(
341+
$changes,
342+
$this->analyzeModuleConfig(
343+
$moduleName,
344+
$before[$moduleName],
345+
$after[$moduleName]
346+
)
347+
);
348+
}
349+
350+
$changes = array_merge(
351+
$changes,
352+
$this->removedModuleConfig(
353+
array_intersect_key($before, array_flip(array_diff(array_keys($before), array_keys($after))))
354+
)
355+
);
356+
357+
$changes = array_merge(
358+
$changes,
359+
$this->addedModuleConfig(
360+
array_intersect_key($after, array_flip(array_diff(array_keys($after), array_keys($before))))
361+
)
362+
);
363+
364+
$this->reportChanges($changes);
365+
return $this->report;
366+
}
367+
}

0 commit comments

Comments
 (0)