Disable SonataUserBundle sonata.user.admin.group service - php

I'm working with SonataAdminBundle and SonataUserBundle.
SonataUserBundle registers a service sonata.user.admin.group which is automatically detected by SonataAdminBundle to set links in the admin dashboard to group CRUD operations.
How can I disable sonata.user.admin.group? I've been following that recipes in Symfony2 documentation:
How to Override any Part of a Bundle - Services and Configuration
Compiling the Container - Creating a Compiler Pass
Working with Container Parameters and Definitions
So far, I have the following code in my bundle definition to add a compiler pass:
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new CompilerPass());
}
And here it is the compiler pass:
<?php
namespace NS\Service\CompilerPass;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class CompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$container->removeDefinition('sonata.user.admin.group');
}
}
I thought that this should work but no. Symfony is throwing an exception telling me that sonata.user.admin.group service does not exist. But it exists, and if I do $container->getDefinition('sonata.user.admin.group') the actual definition is return.
Thanks

Try marking the service as abstract and set its public property to false e.g.
#in any services.yml
services:
sonata.user.admin.group:
abstract: true
public: false
#...
Addition to completeness:
And add to the CompilerPass:
$container->getDefinition('sonata.user.admin.group')->setSynthetic(true);

You've removed the service definition but it's still used on the dashboard. That's why Symfony complains (dashboard tries to access it). It's not an optional service.
You could try to overwrite the dashboard template and avoid using the service? This way service wouldn't be called and you wouldn't have to remove it. If service is not used it's never created.
Alternative would be overloading the service with your implementation.

Related

How to use entity manager in a service past symfony 3.4? [duplicate]

I am developing a Symfony 3 application. Symfony profiler logs tell me:
Relying on service auto-registration for type "App\Entity\SubDir\Category"
is deprecated since version 3.4 and won't be supported in 4.0.
Create a service named "App\Entity\SubDir\Category" instead.
Yet, this is a simple ORM bean:
/**
* #ORM\Entity
* #ORM\Table(name="category")
*/
class Category
{
...
How should I get rid of this issue? Do I really need to declare ORM entities as services in services.yaml? If yes, how?
Update
In fact, my entity is in a sub directory. I have amended my question.
In my service.yaml, I have tried:
App\:
resource: '../src/*'
exclude: '../src/{Entity,Repository,Tests,Entity/SubDir}'
...but to no avail.
Do you have any Classes under Service-auto registration which use an Entity as constructor argument?
That's where your problem comes from.
You need to ask yourself if the concerning class really is a service or just a plain object of which you always create the instance yourself.
If it is not used as a service through the container you have 2 options:
You can exclude this class also through the glob pattern like for example
AppBundle\:
resource: '...'
# you can exclude directories or files
# but if a service is unused, it's removed anyway
exclude: '../../{Entity,PathToYourNotService}'
or you can set the following parameter in your config
parameters:
container.autowiring.strict_mode: true
with this option the container won't try to create a service class with arguments that are not available as services and you will get a decisive error. This is the default setting for sf4
A good example for a class that triggers exactly this error would be a custom event class that takes an entity as payload in the constructor:
namespace AppBundle\Event;
use AppBundle\Entity\Item;
use Symfony\Component\EventDispatcher\Event;
class ItemUpdateEvent extends Event
{
const NAME = 'item.update';
protected $item;
public function __construct(Item $item)
{
$this->item = $item;
}
public function getItem()
{
return $this->item;
}
}
Now if this file isn't excluded specifically the container will try to auto register it as service. And because the Entity is excluded it can't autowire it. But in 3.4 there's this fallback which triggers this warning.
Once the strict_mode is activated the event just won't be available as service and if you tried using it as one an error would rise.

Relying on service auto-registration error on ORM entity

I am developing a Symfony 3 application. Symfony profiler logs tell me:
Relying on service auto-registration for type "App\Entity\SubDir\Category"
is deprecated since version 3.4 and won't be supported in 4.0.
Create a service named "App\Entity\SubDir\Category" instead.
Yet, this is a simple ORM bean:
/**
* #ORM\Entity
* #ORM\Table(name="category")
*/
class Category
{
...
How should I get rid of this issue? Do I really need to declare ORM entities as services in services.yaml? If yes, how?
Update
In fact, my entity is in a sub directory. I have amended my question.
In my service.yaml, I have tried:
App\:
resource: '../src/*'
exclude: '../src/{Entity,Repository,Tests,Entity/SubDir}'
...but to no avail.
Do you have any Classes under Service-auto registration which use an Entity as constructor argument?
That's where your problem comes from.
You need to ask yourself if the concerning class really is a service or just a plain object of which you always create the instance yourself.
If it is not used as a service through the container you have 2 options:
You can exclude this class also through the glob pattern like for example
AppBundle\:
resource: '...'
# you can exclude directories or files
# but if a service is unused, it's removed anyway
exclude: '../../{Entity,PathToYourNotService}'
or you can set the following parameter in your config
parameters:
container.autowiring.strict_mode: true
with this option the container won't try to create a service class with arguments that are not available as services and you will get a decisive error. This is the default setting for sf4
A good example for a class that triggers exactly this error would be a custom event class that takes an entity as payload in the constructor:
namespace AppBundle\Event;
use AppBundle\Entity\Item;
use Symfony\Component\EventDispatcher\Event;
class ItemUpdateEvent extends Event
{
const NAME = 'item.update';
protected $item;
public function __construct(Item $item)
{
$this->item = $item;
}
public function getItem()
{
return $this->item;
}
}
Now if this file isn't excluded specifically the container will try to auto register it as service. And because the Entity is excluded it can't autowire it. But in 3.4 there's this fallback which triggers this warning.
Once the strict_mode is activated the event just won't be available as service and if you tried using it as one an error would rise.

Symfony2 access private services in tests

Currently I'm working on testing some services in Symfony2 and I'm trying to use Guzzle MockPlugin for controlling CURL responses. Symfony version 2.3.8 is used. I've got to an interesting behaviour and I'm not sure if this is a Symfony2 bug or not.
I have these services in services.yml:
lookup_service_client:
class: FOO
public: false
factory_service: lookup_client_builder
factory_method: build
lookup_repository_auth_type:
class: AuthType
arguments: ["#lookup_service_client"]
lookup_repository_cancel_reason:
class: CancelReason
arguments: ["#lookup_service_client"]
payment_service_client:
class: FOO
public: false
factory_service: payment_client_builder
factory_method: build
payment_repository:
class: Payment
arguments: ["#payment_service_client"]
The name of the classes are not important. You can see that both "lookup_service_client" and "lookup_service_client" are PRIVATE services.
I have a test class, which extends Symfony\Bundle\FrameworkBundle\Test\WebTestCase. In one test I need to do something like:
$lookup = $this->client->getContainer()->get('lookup_service_client');
$payment = $this->client->getContainer()->get('payment_service_client');
I expected that, setting those services as PRIVATE, will not let me retrieve the services from container in tests, but the actual result is:
$lookup = $this->client->getContainer()->get('lookup_service_client'); => returns the service instance
$payment = $this->client->getContainer()->get('payment_service_client'); => returns an exception saying: "You have requested a non-existent service"
The only difference between those tow service_client services is that "lookup_service_client" is injected in several other services, while "payment_service_client" is injected in only one other service.
So, the questions are:
Why I can retrieve from container "lookup_service_client", since I've set it to private?
Why I can retrieve "lookup_service_client", but cannot retrieve "payment_service_client" since the only difference is presented above?
Is it a Symfony2 bug that I can access private service?
There were some new changes regarding this in Symfony 4.1:
In Symfony 4.1, we did the same and now tests allow fetching private services by default.
In practice, tests based on WebTestCase and KernelTestCase now access to a special container via $client->getContainer() or the static::$container property that allows to fetch non-removed private services.
You can read more about it in the news post.
While this is not a bug, it is definitely counter intuitive. The manual specifically says:
Now that the service is private, you should not fetch the service
directly from the container:
$container->get('foo');
This may or may not work, depending on how the container has optimized
the service instanciation and, even in the cases where it works, is
deprecated. Simply said: A service can be marked as private if you do
not want to access it directly from your code.
Which is why the core team has decided to make this behavior more consistent and intuitive in Symfony 4:
Setting or unsetting a private service with the Container::set() method is deprecated in Symfony 3.2 and no longer supported in 4.0;
Checking the existence of a private service with the Container::has() will always return false in Symfony 4.0;
Requesting a private service with the Container::get() method is deprecated in Symfony 3.2 and no longer returns the service in 4.0.
2018+ and Symfony 3.4/4.0+ solution
This approach with all its pros/cons is described in this post with code examples.
The best solution to access private services is to add a Compiler Pass that makes all services public for tests. That's it. How does it look in practice?
1. Update Kernel
use Symfony\Component\HttpKernel\Kernel;
+use Symplify\PackageBuilder\DependencyInjection\CompilerPass\PublicForTestsCompilerPass;
final class AppKernel extends Kernel
{
protected function build(ContainerBuilder $containerBuilder): void
{
$containerBuilder->addCompilerPass('...');
+ $containerBuilder->addCompilerPass(new PublicForTestsCompilerPass());
}
}
2. Require or create own Compiler Pass
Where PublicForTestsCompilerPass looks like:
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
final class PublicForTestsCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $containerBuilder): void
{
if (! $this->isPHPUnit()) {
return;
}
foreach ($containerBuilder->getDefinitions() as $definition) {
$definition->setPublic(true);
}
foreach ($containerBuilder->getAliases() as $definition) {
$definition->setPublic(true);
}
}
private function isPHPUnit(): bool
{
// defined by PHPUnit
return defined('PHPUNIT_COMPOSER_INSTALL') || defined('__PHPUNIT_PHAR__');
}
}
To use this class, just add the package by:
composer require symplify/package-builder
But of course, the better way is to use own class, that meets your needs (you might Behat for tests etc.).
Then all your tests will keep working as expected!
Let me know, how that works for you.
Check them in the container:
container:debug lookup_service_client
container:debug payment_service_client
in your example they both have class "FOO", maybe that's the case

Why is Symfony2 (ezpublish5) not recognizing my controller as a service?

I'm trying to create a menu for my page with ezpublish5. I followed this tutorial http://partialcontent.com/Code/working-with-ez-publish-5-subrequests.
I'm pretty new to Symfony, but I have my own bundle there and running, at least it is using my own pagelayout.html.twig.
I understand, what routing does, but I as far as I'm concerned in order to create a menu I need something else, probably a service, so I can do this in my twig-template
{{ render( controller( "myMenuController:myFunction" ) ) }}
So I add this to my my\Bundle\Resources\config\services.yml
parameters:
my_root.menucontroller.class: my\Bundle\Controller\MenuController
services:
my_root.controller:
class: %my_root.menucontroller.class%
arguments: [#ezpublish.view_manager]
calls:
- [setContainer, [#service_container] ]
myalias:
alias: my_root.controller
When I open it in the browser it says:
You have requested a non-existent service "myalias".") in "{% extends "Bundle::pagelayout.html.twig" %}
I checked other repos of ezp5 installations on github, they have pretty much the same yml-setup.
I also realized, that when I make syntax errors on purpose in my services.yml it (while leaving out the call to the controller in the template) it doesn't change anything.
Also I realized, that when I do the same in my\Bundle\DependencyInjection\myBundleExtension.php (which is supposed to load my services.yml file) it doesn't happen anything either.
So I'm getting the feeling something with bundle-setup is wrong, that somehow not everything is loaded correctly. But what could it be?
Somewhere in the docu of symfony2 it says that the load-method in the Bundle\DependencyInjection\xyzExtension.php gets called automatically.
Would anyone have an idea of what could possibly be wrong with my setup? I'm really running out of ideas.
And for the ezpublish5 part.. is this really the best way to create a menu right now?
It does seem like your services are not being loaded.
Symfony relies on a naming convention to load xyzExtension.php. It's tripped me up a few times. You can stick a die statement in xyzExtension.load just to verify it is indeed being called.
If it is not being called than you can either change the extension class name to meet the convention or do what I do and just override the convention in your bundle class.
namespace Cerad\Bundle\GameV2Bundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Cerad\Bundle\GameV2Bundle\DependencyInjection\GameExtension;
class CeradGameV2Bundle extends Bundle
{
public function getContainerExtension()
{
return new GameExtension();
}
}
And of course xyzExtension should have something like:
namespace Cerad\Bundle\GameV2Bundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\Config\FileLocator;
class GameExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
}
public function getAlias() { return 'cerad_game_v2'; }
}
From the command line you can verify your service is getting picked up:
app/console container:debug : grep my_root

Symfony2: get Doctrine in a generic PHP class

In a Symfony2 project, when you use a Controller, you can access Doctrine by calling getDoctrine() on this, i.e.:
$this->getDoctrine();
In this way, I can access the repository of such a Doctrine Entity.
Suppose to have a generic PHP class in a Symfony2 project. How can I retrieve Doctrine ?
I suppose that there is such a service to get it, but I don't know which one.
You can register this class as a service and inject whatever other services into it. Suppose you have GenericClass.php as follows:
class GenericClass
{
public function __construct()
{
// some cool stuff
}
}
You can register it as service (in your bundle's Resources/config/service.yml|xml usually) and inject Doctrine's entity manager into it:
services:
my_mailer:
class: Path/To/GenericClass
arguments: [doctrine.orm.entity_manager]
And it'll try to inject entity manager to (by default) constructor of GenericClass. So you just have to add argument for it:
public function __construct($entityManager)
{
// do something awesome with entity manager
}
If you are not sure what services are available in your application's DI container, you can find out by using command line tool: php app/console container:debug and it'll list all available services along with their aliases and classes.
After checking the symfony2 docs i figured out how to pass your service
in a custom method to break the default behavior.
Rewrite your configs like this:
services:
my_mailer:
class: Path/To/GenericClass
calls:
- [anotherMethodName, [doctrine.orm.entity_manager]]
So, the Service is now available in your other method.
public function anotherMethodName($entityManager)
{
// your magic
}
The Answer from Ondrej is absolutely correct, I just wanted to add this piece of the puzzle to this thread.

Categories