Symfony4 migration: The "doctrine.database_create_command" service is private - php

I'm starting to migrate my application to symfony4 but I have the following deprecation notice in one of my third-party bundle ( tbbcmoneybundle . And I would like to know what to change in order to propose a PR
Currently the build is failing because of these errors (complete report here )
The "doctrine.database_create_command" service is private, getting it from the container is deprecated since Symfony 3.2 and will fail in 4.0. You should either make the service public, or stop using the container directly and use dependency injection instead: 25x
12x in ConfigTest::setUp from Tbbc\MoneyBundle\Tests\Config
6x in ConsoleTest::setUp from Tbbc\MoneyBundle\Tests\Console
3x in ConsoleTest::testRunRatioList from Tbbc\MoneyBundle\Tests\Console
2x in ConsoleTest::testRunRatioFetch from Tbbc\MoneyBundle\Tests\Console
1x in ConfigTest::testHistoryOfFetchedRatio from Tbbc\MoneyBundle\Tests\Config
1x in ConsoleTest::testRunSaveRatio from Tbbc\MoneyBundle\Tests\Console
I guess it's related to this code
$this->runCommand($this->client,'doctrine:database:create');
$this->runCommand($this->client,'doctrine:schema:update --force');
However I don't see see how to fix this and google seems unhelpful on this one.

The problem looks like it comes from the loss of container awareness (if that's a valid phrase) in Symfony 4, which started in Symfony 3.4. This blog talks about restricting container injection in 3.4 and how it will go away in 4.0.
It looks as though someone has opened a PR to upgrade to Symfony 4, but that is failing. (Looks like you're trying to help that along as well.)
According to this Travis integration test that is failing, the commands which extend "ContainerAwareCommand" are the source of the fail.
Which makes sense. The ContainerAwareCommand attempts to inject the Container, which is set to private in Symfony 4 (and deprecated since 3.4) as outlined in the blog post above. A fix, and I think you want to fix this in a PR to TBBC if I read your question correctly, seems to be to remove the extension of ContainerAwareCommand from those command classes and just inject the services necessary. See the new Symfony 4 doc on commands (and note that ContainerAware is no longer an option as it was in 2.8-ish.)
In short, get rid of the extension to ContainerAwareCommand and inject the services used by those commands. (Might need to do some extra configuration to ensure that the services are public.)

Related

Make private and removed service available in tests

I'm trying to make vatin-bundle compatible with Symfony 6.
But the tests fail
The "validator" service or alias has been removed or inlined when the container was compiled. You should either make it public, or stop using the container directly and use dependency injection instead.
It seems this is new in Symfony 6
The container in static::getContainer() is actually a special test container. It gives you access to both the public services and the non-removed private services services.
What is the preferred way to make validator available in tests again?
The only way I found is creating my own alias like
services:
myvalidator:
alias: validator
public: true
and use the new alias. Is there a better way?
If the service is removed, then it's no longer accessible no matter what. It's not a matter of visibility, the service is no longer there. So you need to prevent the service from being removed: creating an alias is the best and simplest way to go about it.
This has been confirmed by maintainers here.
You can create the alias only during testing, and still access the original service. (e.g. ->get('validator'). Once the alias is created, the original service is no longer removed.
I don't think this is something really new in Symfony 6, but it's bee a thing since Symfony 4.4. Although it's true that now on Symfony 6, since it's removes previously deprecated behaviour, things could have changed.

Best way to handle dependencies between components of a PHP framework using Git and Composer

Background
I am developing a framework in PHP. I started by making each component separately so that it can be used independently from the framework.
After creating four libraries A, B, C and D:
A has no dependencies
B and C require A
D requires A, B and C
Now I have some issues when releasing a new version of one library, I may have to change dependencies of others and have to release new versions for them. For example: new version of A means new version of B, C and D.
I looked how other frameworks like Symfony and Laravel solved this issue. I learned that they are using the subtree feature of Git and the replace feature of Composer. It works as follows:
Each component is in a read-only repository with his own composer.json
Each component can require other components but doesn't replace them.
The framework repository uses subtrees to include all components. So no need to require them using composer. But it should require all their dependencies (since this is no longer handled by Compser).
The framework replaces all its components.
I have also noticed that
A component repository contains only the source code (no unit tests !)
Laravel made the component Contracts just to store all the interafces of all component and each component is requiring that.
Questions
Is my explanation of how Laravel and Symfony solved the issue correct ?
Do I really have to remove tests from the components repositories and put them in the framework one ?
If yes, how can someone who wants just to use a single component be sure it passes the tests regardless of the whole framework being passing the wole tests ?
Do I have to make sure that all components dependencies are compatible and require them manually in the framework composer.json ?
What is the point of having a component for Interfaces ? This could not be used standalone anyway !
Is there a better way to solve this problem ?
P.S: here are links to A, B, C and D
Now I have some issues when releasing a new version of one library, I may have to change dependencies of others and have to release new versions for them. For example: new version of A means new version of B, C and D.
You have a multi-repo approach.
Edit of A => new version of A => version bump needed in B, C and D.
I think the most important thing is to get away from using dev-master and versionize your components properly, once they are stablized and ready to be out of dev-phase. Then you might use Composers range operators (caret ^ & tilde ~) to automatically update to the latest released version in a certain major.minor version range. This helps a great deal and takes the tedious manual version updating work out of your hands.
Is my explanation of how Laravel and Symfony solved the issue correct ?
It's not correct. The underlying development concept, publication and consumption of packages work differently, then to what you described.
They use a monolithic repo development style. It's a single repository, which contains code for group of packages. The opposite of the mono-repo is many-repo approach. The alternative are git submodules.
All modules/bundles of a framework and the framework core/kernel are in one repository! For Laravel it's https://github.com/laravel/framework/tree/5.4/src/Illuminate
Each module/bundle folder contains a composer.json and the framework itself contains a composer.json
This allows to "split out" the module folders into standalone read-only repositories. Using a custom git helper, e.g. git subsplit publish like Laravel uses https://github.com/laravel/framework/blob/636020a96a082b80fa87eed07d45c74fa7a4ba70/build/illuminate-split-full.sh or splitsh https://github.com/splitsh/lite, like Symfony uses
The development happens in the main repo.
Finally, from the user/consumer perspective (in the composer.json of your CMS/app whatever), you simply require a module/bundle from the "standalone read-only repository" source. This is many-repo, because your app depends on many repositories.
When you update a dependency using Composer, then Composer replaces your packages with a newer version.
Do I really have to remove tests from the components repositories and put them in the framework one ?
No. You could also leave the tests in the /moduleA/tests folder and adjust your unit test collector.
If yes, how can someone who wants just to use a single component be sure it passes the tests regardless of the whole framework being passing the wole tests ?
Two things. The subject under test is:
(a) the component, which is ideally independently testable and
(b) the framework, which consumes many components and tests functionalities, which rely on functions from multiple components (e.g. a core/kernel). You could also split a kernel out, once it stabilizes and is testable independently. (e.g. your component D)
Do I have to make sure that all components dependencies are compatible and require them manually in the framework composer.json ?
The monorepo developer perspective:
The developer/maintainer of a framework can only release a new version, when all unit-tests of all components and all unit-tests of the framework itself pass, right? Then he can start a subtree split and automatically versionize the new components.
The application developer perspective:
Yes. As the user of components of a monorep you are simply consuming standaloen dependencies (from the read-only repos). That means you have to maintain the versions of the components you require in your composer.json manually or automatically.
What is the point of having a component for Interfaces ? This could not be used standalone anyway !
Good question!
Maybe the developers want to do things differently and "keep things sorted"
Or, they have a bad optimization idea on their minds:
One could argue that interfaces are only development contracts.
When all components are written against interfaces you could simply pull the plug on them, after testing and before doing a production release.
In other words: you could leave the interfaces repository away
and run an interface removal, when you are releasing for production.
Leaving the interfaces repo away would lead to "interfaces X not found" fatal errors. Then you run an "optimizer pass" over the rest of the classes and remove all "implements interfaceX" strings. Less files to include. Less code to parse. Less IO. And now i will probably be killed in the comment section by suggesting this :) And no, Laravel or Symfony are not doing this.
Is there a better way to solve this problem?
I'd suggest to do the following: for a project with <5 components, use multi-repo. If >5 components, go monorepo.
In general there are not so many options to solve this:
git submodules
mono-repo
multi-repo
Each of the approaches has pro's and con's.:
Updating git submodules a.k.a. git version bumping and submodule updating leads to git madness, because it'll be constantly broken. and git madness leads to the dark side. :)
Mono-repo is easy to maintain and easy to publish. It gives you easy maintainace for the developer and multi-repo for the consumer. You can replace/rename/refactor across all modules/components at once.
Many-repo is hard to maintain, when you have a large number of components.
See also:
https://www.tomasvotruba.cz/blog/2017/01/31/how-monolithic-repository-in-open-source-saved-my-laziness/
DrupalCon New Orleans 2016: The Symfony Monolith Repository

Can individual Composer dependencies be suppressed from (auto)loading?

I have a project containing, amongst others, the following composer.json dependencies:
"propel/propel1": "dev-master"`,
"halleck45/phpmetrics": "dev-master"
I recently did a composer update and found that a new version of a library required by PhpMetrics, called Hoa, introduces a new class \EngineException to emulate a new PHP7 class. Unfortunately Propel 1 also defines \EngineException, and so a conflict results.
The correct fix for this would be to upgrade to Propel 2, which uses namespaces. However this is still in alpha and is subject to BC breaks, so is not really workable for me.
My present fix is to lock Hoa to a specific version that does not have the new class:
"hoa/core": "2.15.04.*"
That's not a bad solution, but it isn't entirely satisfying to lock a library to an old version.
In the Hoa code, the only way for the new class not to be loaded is to be running PHP 7, which is again not feasible. However, it also occurs to me that Hoa only needs to be required when PhpMetrics runs. This is a stand-alone code analysis tool and only sits in the root of the project for convenience; the rest of the project does not use this library.
Thus, it would be great if I could call something in Composer to ask that this class is not (auto)loaded, or perhaps something to do the same in the composer.json. It is being needlessly loaded at present - I don't know whether it is being autoloaded incorrectly or whether it is being required manually by Composer.
It may help to know that Hoa classes have been added by Composer to the auto-generated autoload_psr4.php script. As far as I can understand the docs, this means it is autoloaded, and there is nothing in my project that would require any of the Hoa classes.
Fixed by https://github.com/hoaproject/Core/commit/8ed00fe9345c4f8b2679a256926d6d24994ea842.
The new exception architecture introduced in PHP7 [1] has been totally
redesigned [2]. This patch updates the retro-compatibility classes
according to this new architecture. Consequently, the BaseException
class has been removed, along with EngineException and
ParseException. While these latters could be implemented (not as
is), we prefer to, so far, only implement the Throwable interface.
Let see if we can implement (still for the retro-compatibility) the
Error, TypeError and ParseError class.
[1]: https://wiki.php.net/rfc/engine_exceptions_for_php7
[2]: rfc/throwable-interface
I was curious, so I looked it up. Hoa indeed has a broken approach, having the file Core.php always included, by a "file" autoload in composer which in turn includes Consistency.php. The latter defines your class.
You could raise an issue with the developers at Hoa, to use class_exists to check for the method rather than the currection version check they are using. This could cause the propel autoloader to load its own. Another way would be to define their autoloading correctly, but they prefer to load manually as it seems.

ConfigCache::__toString() is deprecated since version 2.7

After updating to Symfony 2.7 I've got deprecated notification in my profiler. Here it is:
It looks like an internal Symfony stuff. Any ideas about how to fix it or it will be fixed in next Symfony patches?
It seems that the issue is located at the "AllowedMethodsRouterLoader" class. This might be an external bundle, so you might be able to update this bundle. If it's your own class, it's as easy as just changing it to using ->getPath() instead of using the ConfigCache instance as a string.

Symfony console application: dependency injection [duplicate]

This question already has an answer here:
How to use DependencyInjection from symfony in stand alone application with commands?
(1 answer)
Closed last year.
A Symfony novice here. After reading some of the Symfony documentation and some answers here at SO, I am now almost completely confused.
I am trying to use the console application component and create a small db-aware console application.
Many people state that in order to use Symfony's DI features it would be enough to inherit my command class not from Symfony\Component\Console\Command\Command but from ContainerAwareCommand.
However when I try this I get a Method Not Found error on an application::getKernel() call.
I have a feeling that DI features are in fact not available in a console application based on the console component. Is there another kind of Symfony console application, for example, based on the full-blown framework?
I very much like the simple framework provided by the console component Symfony\Component\Console\Application. But the question is then - what to do for dependency injection and DBAL? All examples that I find seem to refer to the full Symfony framework and get me just all the more stuck.
Just a quick update on my progress if anybody stumbles upon the same problems.
I incorporated into my project the PHP-DI dependency injection framework, which seems to be working fairly well with no configuration (so far) - it figures out quite a lot by reflection, actually.
The same way, Doctrine\DBAL is included as a standalone library (I opted against the O/RM part of it, as it is really a tiny project and I'm on a much firmer ground with SQL than anything else) and the connection is simply returned by a connection provider which is injected wherever needed by the DI.
One thing I couldn't figure out is how to have the command classes instantiated by the DI library without my help, so I actually had to inject the container itself into my overridden application class and override the getDefaultCommands() where I then pull the instances out of the container manually. Not ideal but will have to do for now.
If your command extends ContainerAwareCommand
...
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
...
class MyCommand extends ContainerAwareCommand
{
The DI container is available with the getContainer() method. (like in a standard controller), ex:
$this->validator = $this->getContainer()->get('validator');
I don't know if your question is still relevant, but I have an answer as I stumbled across the same problem here.
You just have to create the kernel yourself and give it to the \Symfony\Bundle\FrameworkBundle\Console\Application that extends the basic \Symfony\Component\Console\Application.
<?php
// CronRun.php
require __DIR__.'/../../../../vendor/autoload.php';
require_once __DIR__.'/../../../../app/AppKernel.php';
$kernel = new AppKernel('prod', false);
$kernel->loadClassCache();
$application = new \Symfony\Bundle\FrameworkBundle\Console\Application($kernel);
$application->add(new \KingdomHall\TaskBundle\Command\CronCommand());
$input = new \Symfony\Component\Console\Input\StringInput('k:c:r');
$application->run($input);
You could use a solution I just pushed it to packagist.org. Includes full working symfony/dependency-injection. You're welcome to give it a shot. use composer to create your own project composer create-project coral-media/crune project_dir or just clone the repository.
https://packagist.org/packages/coral-media/crune
You only need to install DBAL dependencies (I don't suggest ORM if you don't really need it). Configure connection parameters in .env and just define a service to handle connection. That service can be injected in your Commands using public setMyService($myService) method with #required annotation. Also you could create a Connection class and bind is as parameter in your command constructor.The crune boilerplate also supports autowire and autoconfiguring features.

Categories