26
26
use PHPSemVerChecker \Registry \Registry ;
27
27
use PHPSemVerChecker \Report \Report ;
28
28
use Magento \SemanticVersionChecker \Operation \SystemXml \FieldDuplicated ;
29
+ use RecursiveDirectoryIterator ;
29
30
30
31
/**
31
32
* Analyzes <kbd>system.xml</kbd> files:
@@ -82,7 +83,7 @@ public function analyze($registryBefore, $registryAfter)
82
83
83
84
//process removed files
84
85
$ this ->reportRemovedFiles ($ removedModules , $ registryBefore );
85
-
86
+ $ duplicateNode = [];
86
87
//process common files
87
88
foreach ($ commonModules as $ moduleName ) {
88
89
$ moduleNodesBefore = $ nodesBefore [$ moduleName ];
@@ -93,13 +94,12 @@ public function analyze($registryBefore, $registryAfter)
93
94
$ beforeFile = $ registryBefore ->mapping [XmlRegistry::NODES_KEY ][$ moduleName ];
94
95
$ this ->reportRemovedNodes ($ beforeFile , $ removedNodes );
95
96
}
96
- print_r ('Added Nodes ' );
97
- print_r ($ addedNodes );
97
+
98
98
if ($ addedNodes ) {
99
99
$ afterFile = $ registryAfter ->mapping [XmlRegistry::NODES_KEY ][$ moduleName ];
100
- $ duplicateNode = $ this ->reportAddedNodesWithDuplicateCheck ($ afterFile , $ addedNodes, $ moduleNodesBefore );
101
- print_r ( ' Duplicate node ' . ( $ duplicateNode ? ' found ' : ' not found ' ));
102
- print_r (" After file " . $ afterFile );
100
+ $ duplicateNode = $ this ->reportAddedNodesWithDuplicateCheck ($ afterFile , $ addedNodes );
101
+
102
+ print_r ($ duplicateNode );
103
103
if ($ duplicateNode ) {
104
104
$ this ->reportDuplicateNodes ($ afterFile , $ addedNodes );
105
105
} else {
@@ -111,117 +111,148 @@ public function analyze($registryBefore, $registryAfter)
111
111
}
112
112
113
113
/**
114
- * Check and Report duplicate nodes
114
+ * Get Magento Base directory from the path
115
115
*
116
- * @param $afterFile
117
- * @param $addedNodes
118
- * @param $moduleNodesBefore
119
- * @return bool|void
116
+ * @param string $filePath
117
+ * @return string|null
120
118
*/
121
- private function reportAddedNodesWithDuplicateCheck ( $ afterFile , $ addedNodes , $ moduleNodesBefore )
119
+ private function getBaseDir ( $ filePath )
122
120
{
123
- print_r ('Report Added Nodes function called. ' );
124
- $ isDuplicate = false ;
125
-
126
- foreach ($ addedNodes as $ nodeId => $ node ) {
127
- $ this ->inspectObject ($ node );
128
-
129
- // Check for duplicates by comparing node content except for 'id'
130
- foreach ($ moduleNodesBefore as $ existingNodeId => $ existingNode ) {
131
- if ($ this ->isDuplicateNode ($ node , $ existingNode )) {
132
- $ isDuplicate = true ;
133
- break 2 ; // Break out of both loops if a duplicate is found
134
- }
121
+ $ currentDir = dirname ($ filePath );
122
+ while ($ currentDir !== '/ ' && $ currentDir !== false ) {
123
+ // Check if current directory contains files unique to Magento root
124
+ if (file_exists ($ currentDir . '/SECURITY.md ' )) {
125
+ return $ currentDir ; // Found the Magento base directory
135
126
}
127
+ $ currentDir = dirname ($ currentDir );
136
128
}
137
- print_r ("Duplicate node values: $ isDuplicate " );
138
-
139
- return $ isDuplicate ;
129
+ return null ;
140
130
}
141
131
142
- private function inspectObject ($ object )
132
+ /**
133
+ * Search for system.xml files in both app/code and vendor directories, excluding the provided file.
134
+ *
135
+ * @param string $magentoBaseDir The base directory of Magento.
136
+ * @param string $excludeFile The file to exclude from the search.
137
+ * @return array An array of paths to system.xml files, excluding the specified file.
138
+ */
139
+ private function searchSystemXmlFiles ($ magentoBaseDir , $ excludeFile = null )
143
140
{
144
- $ reflection = new \ReflectionClass ($ object );
145
- $ properties = $ reflection ->getProperties ();
146
- $ methods = $ reflection ->getMethods ();
141
+ $ systemXmlFiles = [];
142
+ $ directoryToSearch = [
143
+ $ magentoBaseDir .'/app/code '
144
+ ];
147
145
148
- echo "\n Properties: \n" ;
149
- foreach ( $ properties as $ property ) {
150
- // echo $property->getName() . "\n" ;
146
+ // Check if 'vendor' directory exists, and only add it if it does
147
+ if ( is_dir ( $ magentoBaseDir . ' /vendor ' ) ) {
148
+ $ directoriesToSearch [] = $ magentoBaseDir . ' /vendor ' ;
151
149
}
152
-
153
- echo "\nMethods: \n" ;
154
- foreach ($ methods as $ method ) {
155
- // echo $method->getName() . "\n";
150
+ foreach ($ directoryToSearch as $ directory ) {
151
+ $ iterator = new \RecursiveIteratorIterator (new RecursiveDirectoryIterator ($ directory ));
152
+ foreach ($ iterator as $ file ) {
153
+ if ($ file ->getfileName () === 'system.xml ' ) {
154
+ $ filePath = $ file ->getRealPath ();
155
+ if ($ filePath !== $ excludeFile ) {
156
+ $ systemXmlFiles [] = $ file ->getRealPath ();
157
+ }
158
+ }
159
+ }
156
160
}
161
+ return $ systemXmlFiles ;
157
162
}
158
163
159
164
/**
160
- * Check if node is duplicate or not
165
+ * Check and Report duplicate nodes
161
166
*
162
- * @param $node
163
- * @param $existingNode
167
+ * @param $afterFile
168
+ * @param $addedNodes
169
+ * @param $moduleNodesBefore
164
170
* @return bool
171
+ * @throws \Exception
165
172
*/
166
- private function isDuplicateNode ( $ node , $ existingNode )
173
+ private function reportAddedNodesWithDuplicateCheck ( $ afterFile , $ addedNodes )
167
174
{
168
- // Extract data from both nodes
169
- $ newNodeData = $ this ->getNodeData ($ node );
170
- $ existingNodeData = $ this ->getNodeData ($ existingNode );
171
- /* echo "\n New Node\n";
172
- print_r($newNodeData);
173
- echo "\n~~~~~~~~~~~~~~~\n";
174
- echo "\n Existing Node\n";
175
- print_r($existingNodeData);*/
176
- // Remove 'id' from both nodes for comparison, including from the path
177
- unset($ newNodeData ['id ' ], $ existingNodeData ['id ' ]);
178
- $ newNodePath = $ this ->removeLastPart ($ newNodeData ['path ' ]);
179
- $ existingNodePath = $ this ->removeLastPart ($ existingNodeData ['path ' ]);
180
-
181
- // print_r($newNodeData());
182
-
183
- // Set the modified paths without the 'id'
184
- $ newNodeData ['path ' ] = $ newNodePath ;
185
- $ existingNodeData ['path ' ] = $ existingNodePath ;
186
-
187
- // Compare the remaining data (skip source_model since it's not provided)
188
- foreach ($ newNodeData as $ key => $ newValue ) {
189
- if (isset ($ existingNodeData [$ key ])) {
190
- $ existingValue = $ existingNodeData [$ key ];
191
- echo "\nNew Value " .$ newValue ." !== Existing Value " . $ existingValue ."\n" ;
192
- if (trim ($ newValue ) == trim ($ existingValue )) {
193
- echo "\nCame in condition. \n" ;
194
- echo "Property ' $ key' does not match between nodes. \n" ;
195
- return true ;
196
- }
175
+ $ baseDir = $ this ->getBaseDir ($ afterFile );
176
+ $ hasDuplicate = false ;
177
+
178
+ foreach ($ addedNodes as $ nodeId => $ node ) {
179
+ $ newNodeData = $ this ->getNodeData ($ node );
180
+ $ nodePath = $ newNodeData ['path ' ];
181
+
182
+ // Extract section, group, and fieldId with error handling
183
+ $ extractedData = $ this ->extractSectionGroupField ($ nodePath );
184
+
185
+ // var_dump($extractedData);
186
+ if ($ extractedData === null ) {
187
+ // Skip the node if its path is invalid
188
+ // echo "Skipping node with invalid path: $nodePath\n";
189
+ continue ;
190
+ }
191
+
192
+ // Extract section, group, and fieldId
193
+ list ($ sectionId , $ groupId , $ fieldId ) = $ extractedData ;
194
+
195
+
196
+
197
+ // Call function to check if this field is duplicated in other system.xml files
198
+ $ isDuplicated = $ this ->isDuplicatedFieldInXml ($ baseDir , $ sectionId , $ groupId , $ fieldId , $ afterFile );
199
+
200
+ if ($ isDuplicated ) {
201
+ $ hasDuplicate = true ;
202
+ echo "\n\nDuplicate found for the field: $ fieldId \n\n" ;
197
203
} else {
198
- echo "Property ' $ key' missing in the existing node. \n" ;
199
- return false ;
204
+
205
+ $ hasDuplicate = false ;
206
+ echo "\n\nNo duplicates for the field: $ fieldId \n" ;
200
207
}
208
+
209
+ // $nodeIds = strrpos($newNodeData['path'],'/');
210
+
211
+ // Extract the substring after the last "/"
212
+ // if ($nodeIds !== false) {
213
+ // $fieldId = substr($newNodeData['path'], $nodeIds + 1);
214
+ // }
215
+ // echo "\nDuplicate $hasDuplicate for the\n";
216
+ // echo "Checking for duplicates for Section: $sectionId, Group: $groupId, Field: $fieldId\n";
217
+
218
+ // return $hasDuplicate;
201
219
}
202
220
203
- // If all properties match (except 'id'), the nodes are duplicates
204
- echo " Nodes are duplicates based on their content. \n" ;
205
- return false ;
221
+ return $ hasDuplicate ;
222
+
223
+ // return $this->isDuplicatedFieldInXml($baseDir, $fieldId, $afterFile) ;
206
224
}
207
225
208
- /* private function getNodeData($node)
226
+ /**
227
+ * Method to extract section, group and field from the Node
228
+ *
229
+ * @param $nodePath
230
+ * @return array|null
231
+ */
232
+ private function extractSectionGroupField ($ nodePath )
209
233
{
210
- return [
211
- 'path' => $node->getPath(),
212
- 'uniqueKey' => $node->getUniqueKey(),
213
- // Add more properties to compare if available, but exclude 'source_model'
214
- ];
215
- }*/
234
+ $ parts = explode ('/ ' , $ nodePath );
216
235
217
- private function removeLastPart ($ path )
218
- {
219
- // Remove the last part of the path (usually the 'id') to compare node structure without it
220
- $ pathParts = explode ('/ ' , $ path );
221
- array_pop ($ pathParts ); // Remove the last part
222
- return implode ('/ ' , $ pathParts ); // Return the path without the 'id'
236
+ if (count ($ parts ) < 3 ) {
237
+ // Invalid path if there are fewer than 3 parts
238
+ return null ;
239
+ }
240
+
241
+ $ sectionId = $ parts [0 ];
242
+ $ groupId = $ parts [1 ];
243
+ $ fieldId = $ parts [2 ];
244
+
245
+
246
+ return [$ sectionId , $ groupId , $ fieldId ];
223
247
}
224
248
249
+ /**
250
+ * Method to get Node Data using reflection class
251
+ *
252
+ * @param $node
253
+ * @return array
254
+ * @throws \ReflectionException
255
+ */
225
256
private function getNodeData ($ node )
226
257
{
227
258
$ data = [];
@@ -316,7 +347,6 @@ private function reportAddedNodes(string $file, array $nodes)
316
347
*/
317
348
private function reportDuplicateNodes (string $ file , array $ nodes )
318
349
{
319
- print_r ('Duplicate Nodes switch case ' );
320
350
foreach ($ nodes as $ node ) {
321
351
switch (true ) {
322
352
case $ node instanceof Field:
@@ -365,4 +395,49 @@ private function reportRemovedNodes(string $file, array $nodes)
365
395
}
366
396
}
367
397
}
398
+
399
+ /**
400
+ * @param string|null $baseDir
401
+ * @param string $sectionId
402
+ * @param string $groupId
403
+ * @param string $fieldId
404
+ * @param string $afterFile
405
+ * @return array
406
+ * @throws \Exception
407
+ */
408
+ private function isDuplicatedFieldInXml (?string $ baseDir , string $ sectionId , string $ groupId , string $ fieldId , string $ afterFile ): array
409
+ {
410
+ if ($ baseDir ) {
411
+ $ systemXmlFiles = $ this ->searchSystemXmlFiles ($ baseDir , $ afterFile );
412
+
413
+ $ result = [];
414
+
415
+
416
+ foreach ($ systemXmlFiles as $ systemXmlFile ) {
417
+ $ xmlContent = file_get_contents ($ systemXmlFile );
418
+ try {
419
+ $ xml = new \SimpleXMLElement ($ xmlContent );
420
+ } catch (\Exception $ e ) {
421
+ echo "\nError parsing XML: " . $ e ->getMessage () . "\n" ;
422
+ continue ; // Skip this file if there's a parsing error
423
+ }
424
+ // Find <field> nodes with the given field ID
425
+ // XPath to search for <field> within a specific section and group
426
+ $ fields = $ xml ->xpath ("//section[@id=' $ sectionId']/group[@id=' $ groupId']/field[@id=' $ fieldId'] " );
427
+
428
+
429
+ if (!empty ($ fields )) {
430
+ echo "\n\nFound match in: $ systemXmlFile \n" ;
431
+ $ result [] = [
432
+ 'status ' => 'patch ' ,
433
+ 'field ' => $ fieldId
434
+ ];
435
+ // break ;
436
+ }
437
+ }
438
+
439
+ }
440
+
441
+ return $ result ;
442
+ }
368
443
}
0 commit comments