@@ -202,6 +202,7 @@ private function isAreaCompatible(string $sourceArea, string $targetArea): bool
202202 return false ;
203203 }
204204
205+
205206 /**
206207 * Check if module is a registered Hyva compatibility module and retrieve its original module.
207208 *
@@ -210,43 +211,98 @@ private function isAreaCompatible(string $sourceArea, string $targetArea): bool
210211 */
211212 private function getOriginalModuleFromCompatRegistry (string $ compatModuleName ): ?string
212213 {
213- // Check if Hyva Compat Registry class exists (soft dependency)
214- if (!class_exists ('\Hyva\CompatModuleFallback\Model\CompatModuleRegistry ' )) {
215- return null ;
214+ // 1. Try Registry (via Emulated Area)
215+ if (class_exists ('\Hyva\CompatModuleFallback\Model\CompatModuleRegistry ' )) {
216+ try {
217+ // Emulate frontend area to load proper DI configuration for CompatModuleRegistry
218+ // as CLI commands run in global scope where frontend/di.xml is ignored.
219+ /** @var \Hyva\CompatModuleFallback\Model\CompatModuleRegistry|null $registry */
220+ $ registry = $ this ->appState ->emulateAreaCode (
221+ Area::AREA_FRONTEND ,
222+ function () {
223+ // Use create() to ensure we get a fresh instance with the emulated configuration.
224+ // get() might return a cached instance from global scope (empty).
225+ return $ this ->objectManager ->create ('\Hyva\CompatModuleFallback\Model\CompatModuleRegistry ' );
226+ }
227+ );
228+
229+ if ($ registry ) {
230+ // Iterate through original modules to find if current module is a registered compat module
231+ // We call getOrigModules inside the emulation callback ideally, but here we got the object
232+ foreach ($ registry ->getOrigModules () as $ originalModule ) {
233+ // Get compat modules for this original module
234+ $ compatModules = $ registry ->getCompatModulesFor ($ originalModule );
235+
236+ // Check exact match first
237+ if (in_array ($ compatModuleName , $ compatModules , true )) {
238+ return $ originalModule ;
239+ }
240+
241+ // Fallback: Case-insensitive check
242+ foreach ($ compatModules as $ compatModule ) {
243+ if (strnatcasecmp ($ compatModuleName , $ compatModule ) === 0 ) {
244+ return $ originalModule ;
245+ }
246+ }
247+ }
248+ }
249+ } catch (\Throwable $ e ) {
250+ // Ignore errors here, continue to manual parsing
251+ }
216252 }
217253
254+ // 2. Fallback: Manual XML parsing because CLI execution might miss frontend/di.xml config
255+ return $ this ->parseCompatModuleXml ($ compatModuleName );
256+ }
257+
258+ /**
259+ * Manual fallback to parse etc/frontend/di.xml for compatibility registration.
260+ * This is required because CLI runs in global scope and might not load frontend DI args.
261+ *
262+ * @param string $moduleName
263+ * @return string|null
264+ */
265+ private function parseCompatModuleXml (string $ moduleName ): ?string
266+ {
218267 try {
219- // Emulate frontend area to load proper DI configuration for CompatModuleRegistry
220- // as CLI commands run in global scope where frontend/di.xml is ignored.
221- $ registry = $ this ->appState ->emulateAreaCode (
222- Area::AREA_FRONTEND ,
223- function () {
224- // Use create() to ensure we get a fresh instance with the emulated configuration.
225- // get() might return a cached instance from global scope (empty).
226- return $ this ->objectManager ->create ('\Hyva\CompatModuleFallback\Model\CompatModuleRegistry ' );
227- }
228- );
268+ $ path = $ this ->componentRegistrar ->getPath (ComponentRegistrar::MODULE , $ moduleName );
269+ if (!$ path ) {
270+ return null ;
271+ }
229272
230- /** @var \Hyva\CompatModuleFallback\Model\CompatModuleRegistry $registry */
231- // Iterate through original modules to find if current module is a registered compat module
232- foreach ($ registry ->getOrigModules () as $ originalModule ) {
233- // Get compat modules for this original module
234- $ compatModules = $ registry ->getCompatModulesFor ($ originalModule );
235-
236- // Check exact match first
237- if (in_array ($ compatModuleName , $ compatModules , true )) {
238- return $ originalModule ;
239- }
273+ $ diPath = $ path . '/etc/frontend/di.xml ' ;
274+ if (!file_exists ($ diPath )) {
275+ return null ;
276+ }
277+
278+ $ xmlContent = file_get_contents ($ diPath );
279+ if (!$ xmlContent ) {
280+ return null ;
281+ }
240282
241- // Fallback: Case-insensitive check (some modules handle naming inconsistently)
242- foreach ($ compatModules as $ compatModule ) {
243- if (strnatcasecmp ($ compatModuleName , $ compatModule ) === 0 ) {
244- return $ originalModule ;
283+ // Simple Regex to extract original_module for this compat module
284+ // We look for the item where compat_module is defined as our module name
285+ // Then extract the sibling item original_module
286+
287+ // Pattern to match the array structure for compatModules argument
288+ // <item name="..." xsi:type="array">
289+ // <item name="original_module" xsi:type="string">Original_Module</item>
290+ // <item name="compat_module" xsi:type="string">Compat_Module</item>
291+ // </item>
292+
293+ // Note: Order of items inside the array is not guaranteed, so we check if the block contains our module name as compat_module
294+
295+ if (preg_match_all ('/<item\s+name="[^"]+"\s+xsi:type="array">(.*?)<\/item>/s ' , $ xmlContent , $ matches )) {
296+ foreach ($ matches [1 ] as $ block ) {
297+ if (str_contains ($ block , $ moduleName )) {
298+ // This block likely belongs to our module. Extract original_module
299+ if (preg_match ('/<item\s+name="original_module"\s+xsi:type="string">([^<]+)<\/item>/ ' , $ block , $ origMatch )) {
300+ return $ origMatch [1 ];
301+ }
245302 }
246303 }
247304 }
248305 } catch (\Throwable $ e ) {
249- // If anything fails (e.g. DI config issues), fallback to standard mapping
250306 return null ;
251307 }
252308
0 commit comments