Symfony event listener not firing - php

I'm scratching my head over this one, so maybe someone can help me out. I've done this before without any issue, but I'm new to Symfony so it's likely I'm missing something this time around.
I'm trying to load an event listener to fire some code whenever I save an entity.
In my app/config/config.yml I put this.
services:
fu_bar.listener:
class: Fu\BarBundle\EventListener\AuthCheckListener
tags:
- { name: doctrine.event_listener, event: postPersist, connection: default }
- { name: doctrine.event_listener, event: preUpdate, connection: default }
In my Fu\BarBundle\EventListener\AuthCheckListener I'm just doing this so I can see I'm hitting these methods, which I'm not.
<?php
namespace Fu\BarBundle\EventListener;
use Doctrine\ORM\Event\LifecycleEventArgs;
class AuthCheckListener {
public function preUpdate(LifecycleEventArgs $args) {
file_put_contents('/tmp/yyy', 'ffdf');
}
public function postPersist(LifecycleEventArgs $args) {
file_put_contents('/tmp/xxx', 'fff');
//$this->syncAuth($args);
}
}
When I save an entity, I'm expecting to see some file(s) in /tmp, but I'm not. It doesn't appear that the event listener is being registered.
What am I missing here?

doctrine:event_listener should be doctrine.event_listener
use dot notation for services and parameters
use colon notation for controllers,views, and these kind of "objects"

Related

Symfony2 get logged in user in doctrine event listener

I have created an event listener class for postPersist, PostUpdate and postRemove methods of doctrine.
I need logged in user id in my class, i have tried injecting #security.context , #security.token_storage and #session
I got circular reference error even i have tried injecting #service_container and use container->get() i got same circular reference error.
ServiceCircularReferenceException: Circular reference detected for > service "doctrine.orm.default_entity_manager"
my code in serviec.yml code is like
my.listener:
class: \projectCreateEventListener
arguments: ["#service_container"]
tags:
- { name: doctrine.event_listener, event: postPersist }
- { name: doctrine.event_listener, event: postUpdate }
- { name: doctrine.event_listener, event: postRemove }
my event listener class is like
class myListener
{
private $container;
public function
__construct(ContainerInterface $container)
{
$this->container = $container;
}
public function prePersist(LifeCycleEventArgs $args)
{
$entity = $args->getEntity();
//Circular reference error
$user = $this->container->get('security.context')-
>getToken()->getUser();
//getToken() is always null
//Circular reference error
$user = $this->container->get('security.token_storage')-
>getToken()->getUser();
//getToken() is always null
//Circular reference error
$userId = $this->container->get('auth.user')-
>getIdentity()['id'];
}
}
Although i am getting logged in user information in my code before $this->persist() in $this->container->get('auth.user')->getIdentity()['id'];
That's a tricky one. When creating the doctrine service the listener is attached while constructing. If the listener you are trying to build uses another service (or some other service down the line) that requires doctrine in any way you get the circular reference.
But you can build around it.
Inject the eventDispatcher into your Listener
Create a custom event (or multiple) http://symfony.com/doc/current/components/event_dispatcher.html#creating-and-dispatching-an-event
Dispatch the event in the prePersist, postPersists methods.
Build another listener that subscribes to your custom event and handle your logic there.
What this achieves is: Your custom event listener will only be initialized when your custom event is actually fired. At that point the crucial services like doctrine are already up and running and you avoid the circular reference problem.
Had a similar issue in my project and solved it this way. Not really sure if it's the most elegant way but it definitely works. (If someone has a better solution i'd welcome it too).

Symfony2 Doctrine Listener postPersist not invoking

I've been following example code to try and get my doctrine event listener to work. However, even though the class is being instantiated into an object (I know this because I logged the __construct, and the __destructor also gets invoked, the postPersist function never does.
My services.yml file has the following (located in AH/Core/SolutionBundle/Resources/config/services.yml):
solutions_core_reverse_sync:
class: AH\Core\SolutionBundle\Listener\ClientSolutionReverseSyncListener
arguments: [#service_container]
tags:
- { name: doctrine.event_listener, event: postPersist }
(Also, the services.yml file is being loaded in AH/Core/SolutionBundle/DependencyInjection/SolutionExtension.php - confirmed because other services are running just fine)
My Entity is just a standard doctrine entity, nothing special about it, except for using a few extra annotation based integrations, like the JMS Serializer. The only thing that is different to most other entities, is the fact that we use the standard SingleTableInheritence from Doctrine, using an #ORM\DiscriminatorMap annotation and the child-entities.
My listener only has a skeleton right now, to test whether it works without anything interfering:
<?php
namespace AH\Core\SolutionBundle\Listener;
use Symfony\Component\DependencyInjection\Container;
use Doctrine\ORM\Event\LifecycleEventArgs;
class ClientSolutionReverseSyncListener
{
protected $container;
public function __construct(Container $container)
{
$this->container = $container;
echo __CLASS__.' __construct'.PHP_EOL;
}
public function postPersist(LifecycleEventArgs $args)
{
echo __CLASS__.' postPersist fired'.PHP_EOL;
}
public function __destruct()
{
echo __CLASS__.' __destruct'.PHP_EOL;
}
}
When testing it, and running the below code, I only see the __construct and the __destruct run (by way of echoing) but not the postPersist:
$cs = $csm->findClientSolutionById(123); // don't worry where $csm comes from
$cs->setUid('do some update: '.rand(0,10000));
$this->em->persist($cs);
Sample output:
AH\Core\SolutionBundle\Listener\ClientSolutionReverseSyncListener __construct
AH\Core\SolutionBundle\Listener\ClientSolutionReverseSyncListener __destruct
I'm at a loss of where I went wrong here, it follows the docs super close:
Doctrine documentation
I also checked this doc, which is similar to the above:
Symfony documentation around listeners
Here is the explanation, and the implementation So, you need to flush the changes, if you want the event to be fired. Persisting entities without flushing them doesn't generate primary key. Also persisting entities doesn't call the database insert operations.

Symfony2 Event Listener Issues

having a bit of trouble understanding Event Listeners. I have the following action in my controller
public function createAction(Request $request)
{
try {
$na_command = strtoupper($request->get('na_command'));
$na_is_connecting = $request->get('na_is_connecting');
// ==== validate (removed) ==== //
$em = $this->getDoctrine()->getManager();
$alert = new AvailabilityAlert();
$alert->setSearchCommand($na_command);
$alert->setIsConnecting($na_is_connecting);
$em->persist($alert);
$em->flush();
return new JsonResponse('Success');
}catch (Exception $e) {
}
}
I have a normal form (not form builder) and I create an Alert from the data and send it to my database. If successful, a Success message is sent back to my ajax.
Here's the problem. If the createAction is successful, I need it to send the alert to another class and do some stuff with it. So it was suggested that an Event Listener could do this for me. So I created a listener to test
<?php
namespace Nick\AlertBundle\EventListener;
use Doctrine\ORM\Event\LifecycleEventArgs;
class AvailabilityAlertListener
{
public function prePersist(LifecycleEventArgs $args)
{
die('Something is being inserted!');
}
}
I then added it to services.yml
services:
doctrine.availability_alert_listener:
class: Nick\AlertBundle\EventListener\AvailabilityAlertListener
arguments: []
tags:
- { name: doctrine.event_listener, event: prePersist }
But then how do I make the createAction listen for this event? I am a bit lost so any advice appreciate. Essentially, at the end of createAction, I want to do something like
include 'uapi_cron_single.php';
AddFlightsAction($alert);
But I dont want to do it like the above because it is messy. But if createAction is successful, I need the alert to be sent to another class, so whats the best way to do this?
Thanks
First of all when you define a service without parameters you don't have to specify arguments: [], you could simply write that
services:
doctrine.availability_alert_listener:
class: Nick\AlertBundle\EventListener\AvailabilityAlertListener
tags:
- { name: doctrine.event_listener, event: prePersist }
Second, do you know that event will be fired before entity is persisted? I suppose that's not what you want (I suppose) as you were writing about trigger an event after object is inserted into DB. So you should modify your service definition as follows
services:
doctrine.availability_alert_listener:
class: Nick\AlertBundle\EventListener\AvailabilityAlertListener
tags:
- { name: doctrine.event_listener, event: postPersist }
and your service class
<?php
namespace Nick\AlertBundle\EventListener;
use Doctrine\ORM\Event\LifecycleEventArgs;
class AvailabilityAlertListener
{
public function postPersist(LifecycleEventArgs $args)
{
die('Something is being inserted!');
}
}
But that's not all ...
Third, this event listener will be raised every time an object, no matter what kind (class) it has, is persisted to db. Of course this is not what you want to.
First solution to check only for "a kind" of object beign persisted is to retrieve entity from LifecycleEventArgs argument and check with instanceof for correctness the class
<?php
namespace Nick\AlertBundle\EventListener;
use Doctrine\ORM\Event\LifecycleEventArgs;
class AvailabilityAlertListener
{
public function postPersist(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
if ($entity instanceof \Your\Bundle\Path\To\AvailabilityAlert) {
/** do something **/
}
}
}
BUT
If you persist that kind of object only there you could also create a service on your own that not follows the logic behind event listener/subscribers and, once persisted an object of AvailabilityAlert, do some action by recalling one of his methods.
Returning to your question
But then how do I make the createAction listen for this event? I am a
bit lost so any advice appreciate.
now you should have understood that event is triggered "automatically" after object is persisted to DB.
One more advice
I've noticed that you want to do
include 'uapi_cron_single.php';
AddFlightsAction($alert);
that's not correct. In Symfony2 you should use autoloading and namespacing to "include" classes from other files.
I would suggest you dispatch custom event and then create custom listener. In Symfony2 docs there is nice entry about it: http://symfony.com/doc/current/components/event_dispatcher/introduction.html
Correct me if i'm wrong, but this listener which you have created is an DoctrineListener. So it will be launched on ANY entity prePersist event. So you would need to determine if entity that you need is persisted. But i'm not 100% sure.

symfony2 service tagged as doctrine.event_subscriber not receiving events when using service with arguments

When I setup the service sme_task.listener.status_change with arguments it is not receiving events.
services:
sme_task.service.task_template:
class: Sme\TaskBundle\Service\TaskTemplateService
arguments: [#doctrine.orm.entity_manager]
sme_task.listener.status_change:
class: Sme\TaskBundle\Listener\StatusChangeListener
arguments: ["#sme_task.service.task_template"]
tags:
- { name: doctrine.event_subscriber, connection: default }
If I remove the arguments the event is reached.
sme_task.listener.status_change:
class: Sme\TaskBundle\Listener\StatusChangeListener
tags:
- { name: doctrine.event_subscriber, connection: default }
Sme\TaskBundle\Listener\StatusChangeListener.php
class StatusChangeListener implements EventSubscriber {
private $taskTemplateService;
public function __construct($taskTemplate=null) {
$this->taskTemplateService=$taskTemplate;
}
[...]
public function onFlush(OnFlushEventArgs $eventArgs) {
throw new \Exception("Event reached");
[... some calls to TaskTemplateService ...]
}
function getSubscribedEvents()
{
return array("onFlush");
}
}
Anyone have an idea why this happens and how I can fix it?
You have circular references. To create EntityManager, all event listeners must be created first. Now as your listener has dependency on a service, which has dependency on entity manager, you get circular reference.
Best way to fix it would be avoid creating these references - you can get entity manager to listener by event arguments, passed to it.
Another way would be to inject service container into listener and get the service only when it's needed.

symfony login event

I try to create an event for when the user enters the system logged,
I have this code :
services:
login_listener:
class: mio\mioBundle\LoginListener
tags:
- { name: kernel.event_listener, event: security.interactive_login, method: onSecurityInteractiveLogin }
<?php
namespace mio\mioBundle;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\EventDispatcher\Event;
class LoginListener
{
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
}
}
?>
but in profiler no called listener what?
Create a service implementing AuthenticationSuccessHandlerInterface and set it as a success handler in your firewall — search for success_handler on the Security Configuration Reference page. You can implement whatever logic you need in the onAuthenticationSuccess() method.
Your code was the proper way. The profiler shows that event was not called probably cause of redirection after the login. The profiler shows you the latest request - the one after redirect. If you'd check profiler info for the last POST request (to login_check) you'd find that the event actually was called.
Working example: http://www.metod.si/login-event-listener-in-symfony2/

Categories