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')
Community
  • 1
  • 1
davidvnog
  • 654
  • 2
  • 11
  • 33

5 Answers5

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".

alepeino
  • 9,551
  • 3
  • 28
  • 48
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

Panuwizzle
  • 111
  • 1
  • 5
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.

Community
  • 1
  • 1
Aken Roberts
  • 13,012
  • 3
  • 34
  • 40
  • 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. – alepeino Jul 19 '17 at 13:09
  • 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](https://github.com/composer/composer/blob/e42e1156d51ca5494b058b1a7b480bc703c4f57a/src/Composer/Autoload/ClassLoader.php#L351). Perhaps a difference in Composer version? – Aken Roberts Jul 19 '17 at 17:03
  • 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 https://github.com/alepeino/composer-optimize – alepeino Jul 19 '17 at 18:28
  • 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. – Aken Roberts Jul 19 '17 at 21:13
0

try it:

"psr-4": {
        ...
        "ModuleA\\": "ModuleA/baseObjects",
        "ModuleB\\": "ModuleB/baseObjects"
 }
YaHui Jiang
  • 130
  • 6
  • It doesn't work, the code above attempts to find it in the current directory, I'm trying to access the parent directory. – davidvnog Jul 13 '17 at 13:53
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');
cre8
  • 13,012
  • 8
  • 37
  • 61