I have a manager and inside a method.
Inside this method, I want to add a listener connect to Doctrine and use this :
$dispatcher = $this->container->get("event_dispatcher");
$dispatcher->addListener(Events::onFlush, function (Event $event) {
var_dump('test');die;
});
But in this case nothing append.
Do you have a solution to accomplish this ? I read a lot of time documentation about listener but I don't understand why didn't work :/
(and I don't want to use EventSubscriber class)
Thank you
Your code seems good, you have to use the doctrine event dispatcher and not the Symfony one.
$doctrineEventManager = $this->em->getEventManager();
$doctrineEventManager->addEventListener(Events::onFlush, New YourEventListenerClass()});;
Related
I need some help to fully test my class that depends on Doctrine.
I have one method in my class that uses that magic method findOneBy... from the Doctrine EntityRepository, as showed below:
But when I run my test I always have this warning:
How can I mock that call? Below I put how EntityManager magic __call method supposed to work:
You can mock magic method __call which is invoked when invoking unacessible methods.
$mock
->expects($this->once())
->method('__call')
->with(
$this->equalTo('findOneByIdShopUrl'), //
$this->equalTo(['5'])
)
->willReturn(['shop' => 'shop info']); // return shop object
Check also http://php.net/manual/en/language.oop5.overloading.php#object.call
The other option is to use setMethods()
$this->getMockBuilder('ShopRepository')->setMethods(['findOneByShopId'])->getMock();
and then the rest logic with methods like will, with etc.
I think that you can replace the magic method findOneByXXXX('identifier') with the real method findOneBy(array('XXXX' => 'identifier')).
That is to say:
$this->shopUrlRepository->findOneByIdShopUrl($this->shop->getId());
To:
$this->shopUrlRepository->findOneBy(array('IdShopUrl' => $this->shop->getId()));
That is a real method. Doctrine documentation
I hope this can help you.
Background: symfony3
I have just stuck in the fact that redirectToRoute and addFlash methods in controller are protected in symfony. I have a separate class for action.
namespace AppBundle\Action;
class Base {
public function __construct($controller) {
$this->controller = $controller;
}
}
As you can see base action class requires a controller. Basically it is logical because action class is part of a controller and should have access to all its methods. However I cannot call $this->controller->addFlash as it is protected. If it is protected then there might be some reason for it. I cannot find it. Can you please hint me how I can change my action class so that it could use controller methods.
The variant about extending action from a controller does not fit me as I have additional functionality in the main controller. It is configured in a proper way.
Update: my goal is to devide controller functionality by responsibility. I invented an action class. My end code look like following:
public function editAction() {
$instance = new \AppBundle\Action\MyController\Edit($this);
return $insance->run();
}
In this case I keep controller clean and not verbose.
Here is a link to Symfony Controller Trait, that you can duplicate, if you really want to work that way.
But since you are injecting a whole symfony controller into your own controllers, you will be better off with extending instead. Injection is used here for injecting separate service by their IDs.
I need to add a FlashBag code $session->getFlashBag()->add('foo', $bar); to every controller, along with the code required to get $bar. I am wondering if there is a better way then copying+pasting the code into every controller? Would there be some sort of master controller?
I'd recommend you to create a listener that will run before every controller that you indicate. Following this guide will show everything you need to set it up:
http://symfony.com/doc/2.0/cookbook/event_dispatcher/before_after_filters.html
http://symfony2.ylly.fr/symfony2-simulate-preexecute-postexecute-filters-actions-jordscream/
You should try implementing a service and registering it for onCoreController, then do $event->getController()->preAction() (or whatever function name you want...) , then you can implement those methods in the controllers that you need functionality in
something like
src/My/Bundle/RequestListener.php:
public function onCoreController(FilterControllerEvent $event) {
$evntController = $event->getController();
if (method_exists($evntController[0], 'beforeFilter')) {
$evntController[0]->beforeFilter();
}
}
Look here for more info
http://symfony.com/doc/2.0/book/internals.html#the-event-dispatcher
http://symfony.com/doc/2.0/book/internals.html
http://symfony.com/doc/current/cookbook/service_container/event_listener.html
Is there a way to inject an event in a service in order to make the service kind of event agnostic?
In prose:
The service says: Hey, give me any Event and i will instanciate it and fire it after i have done my work.
I guess its difficult because the Events can be structured very different:
Event1 expects three parameters in the constructor and Event2 only one.
The purpose would be to reduce dependencies in a bundle and at the same time give it flexibilty for fe custom loggers to hook into the service.
How can i achieve something like this?
Maybe the other way around: fire an event of the service and make the listener event agnostic?
If the caller of the service does know about the arguments of the Event and the listener of the event does know about the event it would be possible to create the event.
I base my example on the example in the Symfony2 cook book: How to extend a Class without using Inheritance.
Normally you would dispatch an event like this:
$event = new HandleUndefinedMethodEvent($this, $method, $arguments);
$this->dispatcher->dispatch('foo.method_is_not_found', $event);
In your service you could add a method to create new events:
public function createEvent($name, $class, $arguments)
{
...
$eventClass = new \ReflectionClass($class);
$event = $eventClass->newInstanceArgs($arguments);
$this->dispatcher->dispatch($name, $event);
}
In this case the service does not need to know about the event, however, as mentioned above both invoker and the listener does have to know about.
I was reading: http://symfony.com/doc/current/cookbook/doctrine/event_listeners_subscribers.html
It appears that using Doctrine event listeners this way is a bit wasteful, because I can not just define a specific entity to listen to and have to check for entity's class within a listener class. This seems like a waste. Is there a way to indicate specific Entity to listen to?
No. You need to include this logic at the top of your listener. This is typically an instanceof check:
public function prePersist($eventArgs)
{
// i.e. using the MongoDB ODM
$doc = $eventArgs->getDocument();
if (!$doc instanceof MyModel) {
return;
}
}
Since Doctrine 2.4 you can use Entity listeners, they are called only for specific entity type.