View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0006561 | OXID eShop (all versions) | 4.10. AutoLoader | public | 2016-12-07 16:53 | 2017-06-29 14:02 |
Reporter | AlexN | Assigned To | |||
Priority | urgent | Severity | crash | Reproducibility | always |
Status | closed | Resolution | fixed | ||
Product Version | 6.0.0-beta.1 | ||||
Fixed in Version | 6.0.0-rc.1 | ||||
Summary | 0006561: Algorithm determining the last class in a module chain is wrong when dealing with namespaces. | ||||
Description | When extending a class (i.e. oxuser) with a class which is in a namespace the chain can be generated. However, the algorithm determining the last class in the chain is wrong. The algorithm works with the $extensionPath and processes the $extensionPath with php's native function basename(...). While this is not an issue when dealing with classes which are not in a namespace this fails when dealing with classes in namespaces. OXID eShop uses the return value of basename(...) as final class name and tries to instantiiate an object. Obviously this fails. | ||||
Steps To Reproduce | 1. Extend class oxuser with a class like "tronet\xnonspacebyspace\Application\Model\useroxuser" 2. Instantiiate a new class. oxNew('oxuser') | ||||
Additional Information | I have developed 2 modules helping to debug this issue. Both can be found as attachment. First activate the module with no namespaces. Second, open /source/index.php?cl=TroFrontendController Third, there should be a method "methodInTrooxuser" Fourth, activate the other module Fifth, open /source/index.php?cl=TroFrontendController Sixth, there shouldn't be a method "methodInNamespaceUser" but the exception: "'EXCEPTION_SYSTEMCOMPONENT_CLASSNOTFOUND'" Seventh: Open file "\source\Core\ModuleChainsGenerator.php" and go to method "createClassExtensions". There add below $lastClass = basename($extensionPath); following: if ($lastClass === 'useroxuser') { $lastClass = str_replace(['\\', '/'], '\\', $extensionPath); } Ninth, open /source/index.php?cl=TroFrontendController Tenth, there should be a method "methodInNamespaceUser" | ||||
Tags | No tags attached. | ||||
Attached Files | |||||
Theme | Not defined | ||||
Browser | Not defined | ||||
PHP Version | Other | ||||
Database Version | Not defined | ||||
|
While looking for a bugfix I was partly successfully. I have added a method "getOriginalClassNameByExtensionPath($extensionPath : string)" to the class "OxidEsales\EshopCommunity\Core\ModuleChainsGenerator" which checks whether the class exists as namespace. This method will be called in "createClassExtensions($classChain : string, $baseClass : string)". $lastClass = $this->getOriginalClassNameByExtensionPath($extensionPath); Thus it is not the finaly solution it probably helps. When using this partly-bugfix it fixes the extend-bug as attached initially. However, when extending a namespace with a namespace class it fails. Unfortunately I don't have more time to do a further analyse. "Fatal error: Class 'trooxuser_parent' not found in [...]". I assume this is caused by the include I am using in the new method. So, instead of including the file we may parse the file instead and look for a pattern like "/^namespace [a-zA-Z0-9\\]{1,}$/" in each line until a "use" or "class" string is found. Following the newly method. /** * Checks whether the class in $extensionPath is a namespace or non-namespace * class. * * @param string $extensionPath * * @return array $originalClassNames * @version 1.0.0 * @since 1.0.0 * @author Alexander Nostadt */ protected function getOriginalClassNameByExtensionPath($extensionPath) { $modulePath = getShopBasePath() . 'modules' . DIRECTORY_SEPARATOR; $namespacedClass = str_replace([ '\\', '/', ], '\\', $extensionPath); $nonNamespaceClass = basename($extensionPath); $originalClassName = ''; if (!class_exists($namespacedClass) && !class_exists($nonNamespaceClass)) { $includePath = $modulePath.$extensionPath; if (!preg_match('/^(.*)\.php$/', $includePath)) { $includePath .= '.php'; } echo $includePath.' '.$extensionPath.' '; include $includePath; } if (class_exists($namespacedClass)) { $originalClassName = $namespacedClass; } else if (class_exists($nonNamespaceClass)) { $originalClassName = $nonNamespaceClass; } return $originalClassName; } |
|
After updating the provided test module to latest standards, the bug is not reproducible (anymore). |