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

筅森魡賤 提交于 2019-12-23 16:05:18

问题


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


回答1:


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




回答2:


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.




回答3:


I think the command should be registered within the bundle, not the app. I think this will work:

# Cravler\/axMindGeoIpBundle/src/Resources/config/services.xml
<services>
  <service
      id="Cravler\MaxMindGeoIpBundle\Command\UpdateDatabaseCommand" 
      class="Cravler\MaxMindGeoIpBundle\Command\UpdateDatabaseCommand" 
      public="false">
      <tag name="console.command" />
  </service>
</services>

The command class extends Symfony\Component\Console\Command\Command.



来源:https://stackoverflow.com/questions/49134340/symfony-4-3rd-party-bundle-commands-are-no-longer-automatically-discovered

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!