View Issue Details

IDProjectCategoryView StatusLast Update
0006561OXID eShop (all versions)4.10. AutoLoaderpublic2017-06-29 14:02
ReporterAlexN 
PriorityurgentSeveritycriticalReproducibilityalways
Status closedResolutionfixed 
Product Version6.0.0-beta.1 
Target VersionFixed in Version6.0.0-rc.1 
Summary0006561: Algorithm determining the last class in a module chain is wrong when dealing with namespaces.
DescriptionWhen 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 Reproduce1. Extend class oxuser with a class like "tronet\xnonspacebyspace\Application\Model\useroxuser"
2. Instantiiate a new class. oxNew('oxuser')
Additional InformationI 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"
TagsNo tags attached.
ThemeNot defined
BrowserNot defined
PHP VersionOther
MySQL VersionNot defined

Activities

AlexN

2016-12-07 16:53

reporter  

testmodules__extendclasses_with_a_namespace.zip (19,948 bytes)

AlexN

2016-12-19 09:59

reporter   ~0011901

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;
    }

QA

2017-06-29 14:02

administrator   ~0012168

After updating the provided test module to latest standards, the bug is not reproducible (anymore).