Skip to content

Commit 3b6e258

Browse files
committed
feat: add Hyva compatibility module retrieval with fallback parsing
1 parent d1d1254 commit 3b6e258

1 file changed

Lines changed: 84 additions & 28 deletions

File tree

src/Service/VendorFileMapper.php

Lines changed: 84 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)