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

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

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

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.

If you are absolutely sure you config is correct and command is still not recognized, try resetting composer's autoloader:
$ composer dump-autoload
This helped in my case.

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.

Related

How do I set the format of log timestamp within Monolog on Symfony framework

I will premise this with the fact that I am new to Symfony but have been using Laravel for some years.
Is it possible to change the format of the log timestamp string through configuration in Symfony (I'm sure it is). I am getting log files out that look like this…
[2022-10-18T09:11:04.228289+00:00] app.DEBUG: a message [] []
I would like to format them like this…
[2022-10-18 09:11:04] app.DEBUG: a message [] []
I am not sure if this is the relevant setting, I suspect it is part of it, but this is the LineFormatter class within Monolog
class LineFormatter extends NormalizerFormatter
{
public const SIMPLE_FORMAT = "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n";
I assume this bit is formatting the timestamp [%datetime%] and is being pulled from a system wide configuration. If this is the case, does anyone know how I can override it?
Using Symfony 6 btw
Thanks in advance
Gary
Welcome on stackoverflow Gary.
Monolog is a library. Symfony imports libraries via a Bundle. You can configure them via the yaml files in the config subdirectory.
To know which options exists, you have three solutions :
Google method. Search the bundle documentation, but in your case, no words about it.
Brutus method: put any value to get an error message. You should see that an option like use_milliseconds exists (I cannot try it without my dev computer), but I already use the Brutus method :)
# config/monolog.yaml
monolog:
foo: bar
Horatio Caine method: look in the source of monolog bundle, there is always a file describing the available options. In your case, I found solution in the `monolog.xml file :
# vendor/symfony/monolog-bundle/Resources/config/monolog.xml
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="monolog.logger" parent="monolog.logger_prototype" public="false">
<argument index="0">app</argument>
<call method="useMicrosecondTimestamps">
<argument>%monolog.use_microseconds%</argument>
</call>
</service>
...
I cannot try it on my phone, but it should solve your problem:
# config/monolog.yaml
monolog:
use_microseconds: false
edit: Since I found this use_microseconds config options, I just find on a old documentation an article about it:
https://symfony.com/doc/3.3/logging/disable_microsecond_precision.html
If you want to remove UTC, you could create your own Formatter. The handler uses a Formatter to format the record before logging it. All Monolog handlers use an instance of Monolog\Formatter\LineFormatter by default but you can replace it. Your new formatter must implement Monolog\Formatter\FormatterInterface. Here is the doc with a sample.
You can extends the LineFormatter and overload the constructor to use your format instead of the default one.

JMS Serializer: overriding default naming strategy in symfony 4 has no effect

I found this thread proposing a neat way of overriding globally the default naming strategy in config.yml
but this is for symfony 3 and I am on symfony 4 so I added the line to my config > packages > jms_serializer.yaml but this has no effect at all.
jms_serializer:
visitors:
xml_serialization:
format_output: '%kernel.debug%'
property_naming:
id: 'jms_serializer.identical_property_naming_strategy'
Does anyone understand why ?
I do dependency injection of SerializerInterface $serializer to use the serializer as it is not possible to call the service from AbstractController in SF4. Controller is deprecated in SF4.
Try removing var/cache manually. When I cleared cache with cache:clear command it didn't work, but after I cleaned it manually it did!
I hope this solution will help you too.
Add jms_serializer.camel_case_naming_strategy.class: JMS\Serializer\Naming\IdenticalPropertyNamingStrategy to your parameters configuration.

class PHPUnit\Framework\ExpectationFailedException not found

when I try to run a failed test with this command :
./vendor/bin/phpunit
I get this Fatal Error :
PHPUnit 5.7.20 by Sebastian Bergmann and contributors.
PHP Fatal error: Class 'PHPUnit\Framework\ExpectationFailedException'
not found in /var/www/zend/vendor/zendframework/zend-
test/src/PHPUnit/Controller/AbstractControllerTestCase.php on line 444
Your version of phpunit is probably too old for your version of Zend. The class PHPUnit\Framework\ExpectationFailedException have been renamed in PhpUnit 6.X from PHPUnit_Framework_ExpectationFailedException to ExpectationFailedException
Please check your PhpUnit version: phpunit --version, it should be 6.X. Update it to the last version to avoid this error.
This is "fixed" by a script in Zend\Test called phpunit-class-aliases.php but it's not configured properly IMHO since it's in the autoload-dev section (meaning it doesn't propagate out to other projects.)
So, in your project composer.json, do something like this:
"autoload-dev": {
"files": [
"vendor/zendframework/zend-test/autoload/phpunit-class-aliases.php"
]
},
Then composer install
N.B. Zend\Test has a pull request that fixes this very thing, but they're saying it's PHPUnit's fault (Shame on you PHPUnit 4 for... idunno... having the wrong class name according to Zend\Test) So, I've done it instead: composer require illchuk/phpunit-class-aliases
This is a configuration flaw in zend-test. It consumes classes from Phpunit 6 but per it's Composer requirements, Phpunit before that version are OK to require:
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0",
Most likely as your system because of the PHP version does not satisfy the requirements of Phpunit 6, the next lower version was installed.
As the code in the base test case (https://github.com/zendframework/zend-test/blob/master/src/PHPUnit/Controller/AbstractControllerTestCase.php#L444) makes use of Phpunit 6 classes, I strongly assume that when the configuration flaw is made aware to the Zend-Test project, you won't be even able to install on your system any longer.
Therefore upgrade to a recent PHP version and then run
composer update
If you're stuk with the PHP version, downgrade zend-test to a version that supports an older Phpunit version. I don't know that project well, so it's just a suggestion, I don't know if such a version exists or can't even recommend one.
I filed a report, perhaps using that one class was an oversight or there is a less hard way to resolve the dependency: https://github.com/zendframework/zend-test/issues/50

`FeatureContext` context class not found and can not be used.

I'm new with symfony2 and i wnat to test my app using behat but when I followed the official install in this link http://docs.behat.org/en/latest/cookbooks/1.symfony2_integration.html#installing-and-enabling-symfony2-extension
i got this error :
[Behat\Behat\Context\Exception\ContextNotFoundException]
FeatureContext context class not found and can not be used.
it was just after the first line and when i ran the bin/behat command.
When using the Symfony2Extension, you are responsible for handling the autoloading. Make sure the FeatureContext class can be autoloaded by changing your composer.json autoload configuration and running composer dump-autoload.

Imagine Bundle conflict minimum

I'd like to install liip/imagine-bundle in my symfony 2 project. But in order to make barcodes, I installed previously MopaBarcodeBundle.
MopaBarcodeBundle requires "avalanche123/imagine-bundle" which requires imagine/imagine: v0.4.1
And
LiipImagineBundle requires imagine/imagine: ~0.5,<0.7
Obviously composer detects the conflict, as he cannot unistall v0.4.1, and that version is not enough for LiipImagine.
I'd like to know how I could bypass this. Create sorts of aliases in composer and keep the two versions on my project ? I'm not a pro in version management, so I guess this is not possible.
Thank you very much for any help.
Ok, after some code inspection i figured out a way around. MopaBarcodeBundle doesn't really requires avalanche123/imagine-bundle, but it uses it in the service declaration. (To make the link with Imagine classes).
So I changed the service.xml file containing the BarcodeService declaration.
<parameter key="imagine.gd.class">Imagine\Gd\Imagine</parameter>
<service id="imagine" alias="imagine.gd" />
<service id="imagine.gd" class="%imagine.gd.class%" />
I guess thoses lines could be factorised, but i chose to keep it as it was done in avalanche123.
Also a constant from avalanche was used in 5th argument, I changed it to :
<argument>%kernel.root_dir%../web</argument>
Finally I removed avalanche, and then install a newer version of imagine/imagine

Resources