Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony 4 - 3rd-party bundle commands are no longer automatically discovered

According to the documentation, a command class must extend Command or ContainerAwareCommand to be automatically discovered and registered (provided its bundle is registered in the Kernel, of course).

Since Symfony 4+, this discovery doesn't work as expected.

Try this:

composer create-project symfony/skeleton test-maxmind-sf4
cd test-maxmind-sf4
composer req cravler/maxmind-geoip-bundle dev-master
php bin/console list

You will notice that:

  • cravler:maxmind:geoip-update is not registered (nothing under a "cravler" namespace
  • Cravler\MaxMindGeoIpBundle\Command\UpdateDatabaseCommand extends ContainerAwareCommand
  • Bundle Cravler\MaxMindGeoIpBundle\CravlerMaxMindGeoIpBundle is registered in config/bundles.php for all environments (auto-generated recipe)

Now when I do exactly the same thing with Symfony 3, everything works properly.

composer create-project symfony/skeleton test-maxmind-sf3 ^3.0
cd test-maxmind-sf3
composer req cravler/maxmind-geoip-bundle dev-master
php bin/console list

What's missing there?

Thank you,

Ben

like image 463
Ben Avatar asked Mar 06 '18 15:03

Ben


2 Answers

From the UPGRADE FROM to 4.0 Guide here:

Relying on convention-based commands discovery is not supported anymore. Use PSR-4 based service discovery instead.

Before:

# app/config/services.yml
services:
    # ...

    # implicit registration of all commands in the `Command` folder

After:

# app/config/services.yml
services:
    # ...

    # explicit commands registration
    AppBundle\Command\:
        resource: '../../src/AppBundle/Command/*'
        tags: ['console.command']

Hope this help

like image 139
Matteo Avatar answered Sep 23 '22 12:09

Matteo


Basically you have to add a few things to your bundle's services file in order to autoconfig your services. Following the example in config/services.yaml:

# Cravler/MaxMindGeolpBundle/Resources/config/services.xml
<services>
    <defaults autowire="true" autoconfigure="true" public="false" />
    <prototype 
        namespace="Cravler\MaxMindGeoIpBundle\" 
        resource="../../*" 
        exclude="../../*/{Entity,Migrations,Tests}" />

    <service id="cravler_max_mind_geo_ip.service.geo_ip_service"
             public="true"
             class="Cravler\MaxMindGeoIpBundle\Service\GeoIpService">
    </service>
</services>

Clear the cache and your command should be there.

And then of course you should probably tweak the command itself and inject the ip service instead of locating it.

I did poke around a bit and did not find this approach documented anywhere. And as I mentioned in the comments, all the bundles I did check still explicitly defined their command services. So I'm not sure if this approach is discouraged or not.

Update: as @Matteo said in their answer, prior to 4.0 any classes defined in the Command directory were treated as commands. This scanning was considered to be magical and removed. However, around the same time, Harry Potter was added to the core team and magic was his thing. So the scanning of the Command directory was replaced with all sorts of auto wiring and auto tagging spells.

like image 35
Cerad Avatar answered Sep 24 '22 12:09

Cerad