Composer autoload - load class from parent directory
Asked Answered
Y

5

8

I'm currently working on a Laravel project that needs to access classes from its parent directory.

composer.json > PSR-4:

    "psr-4": {
        ...
        "ModuleA\\": "../ModuleA/baseObjects",
        "ModuleB\\": "../ModuleB/baseObjects"
    }

Example file structure:

/var/www
 +- /xxx (project)
     +- /ModuleA
        +- /baseObjects
            - configClass.inc
     +- /ModuleB
        +- /baseObjects
            - configClass.inc
     +- /laravel
        - composer.json

I run composer dump-autoload but the project still can't find ModuleA\configClass neither ModuleB\configClass.

Furthermore, inside my autoload_psr4.php, the above gets referenced as following:

'MobuleA\\' => array($baseDir . '/../MobuleA/baseObjects')
'MobuleB\\' => array($baseDir . '/../MobuleB/baseObjects')
Yt answered 7/7, 2017 at 9:17 Comment(1)
try "": "src(main folder i guess its)/" no need to initialize the modules just add folder and /Alluvion
F
4

PSR-4 requires the loaded files to have a namespaced class, and the namespace structure has to match the directory structure, relative to the "base directory" defined in the configuration (http://www.php-fig.org/psr/psr-4/).

So, in file /var/xxx/ModuleA/baseObjects/configClass.inc should be the class

namespace ModuleA\baseObjects;

class configClass {
    ...
}

Then in var/www/laravel/composer.json you could have

    "psr-4": {
        "App\\": "app/",
        "ModuleA\\": "../ModuleA"
    }

Which means: "directory ../ModuleA should be the root for ModuleA namespace, then follow subnamespaces by matching subdirectories from there".

Fiance answered 14/7, 2017 at 13:58 Comment(0)
Y
3

Use classmap autoload will solve this problem.

{
...
"autoload": {
        "classmap": ["ModuleA/", "ModuleB/"]
    }
}

It could be used with PSR-4

{
    ...
    "autoload": {
            "psr-4": { 
                "Acme\\": "src/Acme/"
            },
            "classmap": ["ModuleA/", "ModuleB/"]
        }
    }

Ref: https://getcomposer.org/doc/04-schema.md#classmap

Youthful answered 19/7, 2017 at 3:1 Comment(0)
S
2

The problem you're experiencing is not related to parent directories. In fact, your Composer.json autoload configuration is correct for your directory structure.

The problem is the .inc file extension, which is incompatible with the PSR-4 specification. More info here: How To Make Composer (PSR-4) To Work With ".class.php" Extension?

If you cannot update your source code to match the PSR-4 spec, you can use Class Mapping:

The classmap references are all combined, during install/update, into a single key => value array which may be found in the generated file vendor/composer/autoload_classmap.php. This map is built by scanning for classes in all .php and .inc files in the given directories/files.

You can use the classmap generation support to define autoloading for all libraries that do not follow PSR-0/4. To configure this you specify all directories or files to search for classes.

So your config might look like:

"autoload": {
    "classmap": [
        "../ModuleA/baseObjects",
        "../ModuleB/baseObjects"
    ]
}

Remember, if you use class mapping, you'll need to run composer dump-autoload any time you change composer.json, add a class, modify a class' name/filename/path, etc.

Extra: as pointed out by @alepeino, using autoloader optimization will generate a class map from any PSR-0 and PSR-4 autoload definitions, using the same underlying code that classmap autoload uses. This will "allow" you to use PSR-4 autoloader and the .inc extension. This will still require you to run composer dump-autoload --optimize every time you make a file change, though, just like classmap.

Best recommendation: change your source code to follow PSR-4 specifications, and use the .php extension.

Next best if you can't do that: use classmap for autoloading.

Stipitate answered 19/7, 2017 at 2:52 Comment(4)
I thought so I first, so I tried it, and found that although the PSR-4 specification says the file extension "MUST" be ".php", composer actually loaded a ".inc" correctly.Fiance
I'd like to see the code you used tested for testing. I did a basic PSR-4 set up matching the directory structure in question, and then changed one of the class extensions to .inc and it could no longer be found. The autoloader explicitly sets the extension. Perhaps a difference in Composer version?Stipitate
It turns out I did my first test in a Laravel project, then again tried in a bare new ad-hoc project and wouldn't work. My original composer.json had optimize-autoloader on. See github.com/alepeino/composer-optimizeFiance
Aha! Looking at Composer's source again, optimize-autoloader and equivalent end up running the class mapper across all PSR-0 & PSR-4 directories, which will look for .inc extension files.Stipitate
E
0

According to this answer you can add it in the index.php file:

$loader = require 'vendor/autoload.php';
$loader->add('Namespace\\Somewhere\\Else\\', __DIR__);
$loader->add('Namespace\\Somewhere\\Else2\\', '/var/www/html/xxx');
Emasculate answered 13/7, 2017 at 14:16 Comment(0)
R
-1

try it:

"psr-4": {
        ...
        "ModuleA\\": "ModuleA/baseObjects",
        "ModuleB\\": "ModuleB/baseObjects"
 }
Raybourne answered 7/7, 2017 at 10:47 Comment(2)
It doesn't work, the code above attempts to find it in the current directory, I'm trying to access the parent directory.Yt
Wrong answer, short explanation. Downvoted.Etam

© 2022 - 2024 — McMap. All rights reserved.