I have successfully set up an Entity Event Listener in Symfony 3.4. I registered the service like this, in the Resources/config/services.yml of a separate bundle:
services:
resource.listener:
class: Company\ResourceManagementBundle\EventListener\Entity\ResourceUpdateListener
arguments: ["@security.token_storage"]
tags:
- { name: doctrine.event_listener, event: preUpdate, method: preUpdate }
- { name: doctrine.event_listener, event: postUpdate, method: postUpdate }
I also added the necessary code in the Entity:
/**
* @ORM\EntityListeners(
* {"Company\ResourceManagementBundle\EventListener\Entity\ResourceUpdateListener"}
* )
*/
class Resource implements UserInterface
{
Then in my Event Listener, I created a constructor with Token Storage as the only parameter, type-hinted with the TokenStorageInterface. Here is my event Listener:
namespace Company\ResourceManagementBundle\EventListener\Entity;
use Company\ResourceManagementBundle\Service\UserNoteLogger;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use Symfony\Component\Security\Csrf\TokenStorage\TokenStorageInterface;
class ResourceUpdateListener
{
protected $fields;
private $token_storage;
function __construct(TokenStorageInterface $token_storage)
{
$this->token_storage = $token_storage;
}
public function preUpdate(Resource $resource, PreUpdateEventArgs $args)
{
$entity = $args->getEntity();
if ($entity instanceof Resource) {
$changes = $args->getEntityChangeSet();
}
return $this->setFields($entity, $args);
}
public function postUpdate(Resource $resource, LifecycleEventArgs $args)
{
$entity = $args->getEntity();
$hasChanged = false;
if ($entity instanceof Resource) {
foreach ($this->fields as $field => $detail) {
if($detail[0] == null) {
//continue;
} else {
$hasChanged = true;
}
}
if ($hasChanged == true) {
$userNoteLog = new UserNoteLogger($args->getEntityManager(), $this->token_storage);
$comment = "The resource, " . $resource->getFullName() . ", was changed by the user, " . $this->token_storage->getToken()->getUser()->getFullName();
$userNoteLog->logNote($comment, $resource);
}
}
}
public function setFields($entity, LifecycleEventArgs $eventArgs)
{
$this->fields = array_diff_key(
$eventArgs->getEntityChangeSet(),
[ 'modified'=>0 ]
);
return true;
}
}
This is the error I receive:
Type error: Argument 1 passed to Company\ResourceManagementBundle\EventListener\Entity\ResourceUpdateListener::__construct() must implement interface Symfony\Component\Security\Csrf\TokenStorage\TokenStorageInterface, none given, called in /var/www/sites/sentient02/vendor/doctrine/doctrine-bundle/Mapping/ContainerAwareEntityListenerResolver.php on line 83
This error does not go away, as long as the Token Storage parameter exists in the constructor.
If you look at the EventListener code above, I am trying to log information every time the Entity changes during the update, and this information needs to know the name of the logged in user.