问题
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