Skip to content

Commit e3ae55e

Browse files
committed
Added analyzer for et_schema files
1 parent 5663771 commit e3ae55e

12 files changed

+595
-1
lines changed

src/Analyzer/EtSchemaAnalyzer.php

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

src/DbSchemaReport.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ public function __construct()
2424
$this->differences['system'] = $levels;
2525
$this->differences['xsd'] = $levels;
2626
$this->differences['less'] = $levels;
27+
$this->differences['etSchema'] = $levels;
2728
}
2829
}

src/DbSchemaReporter.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,6 @@ public function output(OutputInterface $output)
3030
$this->outputReport($output, $this->report, 'system');
3131
$this->outputReport($output, $this->report, 'xsd');
3232
$this->outputReport($output, $this->report, 'less');
33+
$this->outputReport($output, $this->report, 'etSchema');
3334
}
3435
}

src/Finder/FinderDecoratorFactory.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public function create(): FinderDecorator
2727
'/etc/adminhtml/system.xml',
2828
'/etc/*.xsd',
2929
'/view/*/*/*/*.less',
30+
'et_schema.xml'
3031
],
3132
[
3233
'ui_component',

0 commit comments

Comments
 (0)