Search code examples
phpsymfonycomposer-phpsonata

Composer class_alias and dump-autoload --classmap-authoritative, class SonataDoctrineSymfonyBundle not found?


I have a strange problem in production, where composer dump-autoload --no-dev --classmap-authoritative produces a classmap autoloader where classes defined using class_alias are not dumped. For example, take this two files from a real Symfony Bundle:

The autoloader contains the first class:

root@09cc7fdd330c:/var/www/html# cat vendor/composer/autoload_classmap.php | grep -i SonataDoctrineBundle
    'Sonata\\Doctrine\\Bridge\\Symfony\\Bundle\\SonataDoctrineBundle' => $vendorDir . '/sonata-project/doctrine-extensions/src/Bridge/Symfony/Bundle/SonataDoctrineBundle.php',
    'Sonata\\Doctrine\\Bridge\\Symfony\\SonataDoctrineBundle' => $vendorDir . '/sonata-project/doctrine-extensions/src/Bridge/Symfony/SonataDoctrineBundle.php',

... but not the second one.

As a consequence, I'm getting errors in production:

PHP Fatal error: Uncaught Error: Class 'Sonata\Doctrine\Bridge\Symfony\SonataDoctrineSymfonyBundle' not found in /var/www/html/src/Kernel.php:38

Question is: why I cannot autoload class SonataDoctrineSymfonyBundle?

(I can fix this problem changing this specific class of course, but I don't know where class_alias maybe used across the entire vendor directory).


Solution

  • The composer dump-autoload command with the --classmap-authoritative command line argument prevents any other auto-loading next to the classmap.

    This mechanism is part of the Composer Autoloader optimization¹, more specifically, it is the Optimization Level 2/A: Authoritative class maps².

    This option [-a, --classmap-authoritative] says that if something is not found in the classmap, then it does not exist and the autoloader should not attempt to look on the filesystem according to PSR-4 rules.

    When Composer generates the class-map, it does not take files with class_alias() directives into account³. That means, classes which names only appear as parameters to calls of class_alias() do not become part of the class-map.

    As it seems you don't have the requirement to use this autoloader optimization and it is incompatible with the class_alias use, an alternative is to use Composer autoload optimization level 1 only:

    $ composer dump-autoload --no-dev --optimize
    

    (use of --optimize (short: -o) command line argument)

    Otherwise it might work using concrete classes instead of class_alias(), but this depends if the library in use supports a different, more static alternative. If so however, then generating the "real" classes before dumping the classmap may help you retain the optimization level 2/A.


    ¹ Composer Autoloader optimization

    ² Optimization Level 2/A: Authoritative class maps

    ³ at least not at the time of writing this answer per its source, with additional discussion of the topic in Support for class aliases #5873