I have an entity listener declared with annotation
...
* #ORM\EntityListeners({ "EnvBundle\Listener\UserListener" })
*/
class User implements UserInterface, \Serializable
{
...
and since that listener should have a parameter injected, say a string, I declared it as a service in the service.yml file
services:
env.listener.user:
class: EnvBundle\Listener\UserListener
arguments: ['humpty dumpty']
Listener is roughly like this
<?php
namespace EnvBundle\Listener;
use Doctrine\ORM\Event\LifecycleEventArgs;
use EnvBundle\Entity\User;
class UserListener
{
public function __construct(string $s)
{
dump('no good: ' . $s);
}
public function prePersist(User $entity, LifecycleEventArgs $args)
{
$em = $args->getEntityManager();
dump($entity);
// die;
}
}
Result is that the parameter injected via the service is ignored and I get the following error
Type error: Argument 1 passed to
EnvBundle\Listener\UserListener::__construct() must be of the type
string, none given
Once I declare the constructor without parameter it gets executed. I can't find out what I'm missing to get the parameters injected into the entity listener.
Edit: by checking debug:container the service does exist
Any suggestion?
Related
Here is my code for my class listener :
<?php
namespace AppBundle\EventSubscriber;
use Lolautruche\PaylineBundle\Event\PaylineEvents;
use Lolautruche\PaylineBundle\Event\ResultEvent;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class PaymentListener implements EventSubscriberInterface
{
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public static function getSubscribedEvents()
{
return [
PaylineEvents::WEB_TRANSACTION_VERIFY => 'onTransactionVerify',
];
}
public function onTransactionVerify(ResultEvent $event)
{ break;
// You can access to the result object from the transaction verification.
/** #var \Lolautruche\PaylineBundle\Payline\PaylineResult $paylineResult */
$paylineResult = $event->getResult();
$transactionId = $paylineResult->getItem('[transaction][id]');
if (!$paylineResult->isSuccessful()) {
break;
if ($paylineResult->isCanceled()){
$this->logger->info("Transaction #$transactionId was canceled by user", ['paylineResult' => $paylineResult->getResultHash()]);
}
elseif ($paylineResult->isDuplicate()){
$this->logger->warning("Transaction #$transactionId is a duplicate", ['paylineResult' => $paylineResult->getResultHash()]);
}
else {
$this->logger->error("Transaction #$transactionId was refused by bank.", ['paylineResult' => $paylineResult->getResultHash()]);
}
return;
}
break;
// Transaction was validated, do whatever you need to update your order
// ...
// Assuming you have set a private data with "internal_id" key when initiating the transaction.
$internalId = $paylineResult->getPrivateData('idCommande');
$repoCommande = $this->getDoctrine()->getManager()->getRepository('CommandeBundle:Commande');
$commande = $repoCommande->find($id);
$commande->setValide(1);
$em = $this->getDoctrine()->getManager();
$em->persist($commande);
$em->flush();
$this->logger->info("Transaction #$transactionId is valid. Internal ID is $internalId");
}
}
then I declared it as a service
services:
app.payment_listener:
class: AppBundle\EventSubscriber\PaymentListener
arguments: ["#LoggerInterface"]
tags:
- { name: kernel.event_subscriber }
But the arguments is not good. The constructor asks a loggerInterface argument and it returns me the following error :
ServiceNotFoundException in CheckExceptionOnInvalidReferenceBehaviorPass.php line 58: The service "app.payment_listener" has a dependency on a non-existent service "loggerinterface".
I explain what I would like to do, in fact I want use the payline bundle but I am stuck here.
Please, help me.
When you're passing an argument to constructor, as _construct(LoggerInterface $logger) you're telling that $logger argument can be any object whose class is the child of the LoggerInterface. So, in your service definition you can pass any logger service (#logger service, for example), not the interface itself. The answer to your question is, pass #logger service from Monolog bridge (or any other service name, which extends the LoggerInterface).
You can find more information here.
I'm using FOSUserBundle on Symfony2.
I extended the User class to have additional fields, therefore I also added the new fields in the twigs.
One of those fields is a licence code. When a user fills in that field I want to perform a connection to DB to look if that license is valid. If not returns an error, if yes creates an event in the "licenceEvents" table assigning the current user to that license.
[EDIT] As suggested I created a custom validator (which works like a charm), and I'm now struggling with the persisting something on DB once the user is created or updated.
I created an event listener as follows:
<?php
// src/AppBundle/EventListener/UpdateOrCreateProfileSuccessListener.php
namespace AppBundle\EventListener;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\FormEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Doctrine\ORM\EntityManager; //added
class UpdateOrCreateProfileSuccessListener implements EventSubscriberInterface
{
private $router;
public function __construct(UrlGeneratorInterface $router, EntityManager $em)
{
$this->router = $router;
$this->em = $em; //added
}
/**
* {#inheritDoc}
*/
public static function getSubscribedEvents()
{
return array(
FOSUserEvents::REGISTRATION_COMPLETED => array('onUserCreatedorUpdated',-10),
FOSUserEvents::PROFILE_EDIT_COMPLETED => array('onUserCreatedorUpdated',-10),
);
}
public function onUserCreatedorUpdated(FilterUserResponseEvent $event)
{
$user = $event->getUser();
$code = $user->getLicense();
$em = $this->em;
$lastEvent = $em->getRepository('AppBundle:LicenseEvent')->getLastEvent($code);
$licenseEvent = new LicenseEvent();
// here I set all the fields accordingly, persist and flush
$url = $this->router->generate('fos_user_profile_show');
$event->setResponse(new RedirectResponse($url));
}
}
My service is like follows:
my_user.UpdateOrCreateProfileSuccess_Listener:
class: AppBundle\EventListener\UpdateOrCreateProfileSuccessListener
arguments: [#router, #doctrine.orm.entity_manager]
tags:
- { name: kernel.event_subscriber }
The listener is properly triggered, manages to create the connection to DB as expected, but gives me the following error
Catchable Fatal Error: Argument 1 passed to AppBundle\EventListener\UpdateOrCreateProfileSuccessListener::onUserCreatedorUpdated()
must be an instance of AppBundle\EventListener\FilterUserResponseEvent,
instance of FOS\UserBundle\Event\FilterUserResponseEvent given
I must be missing something very stupid...
Another question is: I don't want to change the redirect page, so that if the original page was the "email sent" (after a new user is created) let's go there, otherwise if it's a profile update show the profile page.
Using Symfony 2.5.3. I'm trying to send a 'welcome' e-mail when someone has succesfully registered(FOS Userbunde), using an EventListener. The event fired is fos_user.registration.success.
So I added a service:
mycustom_user.registration_success:
class: Mycustom\UserBundle\EventListener\RegistrationListener
arguments: [#mycustom_user.mailer]
tags:
- { name: kernel.event_listener, event: fos_user_registration_success, method: onRegistrationSuccess}
The listener itself:
namespace Mycustom\UserBundle\EventListener;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\UserEvent;
use FOS\UserBundle\Event\FormEvent;
use Mycustom\UserBundle\Mailer\Mailer;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class RegistrationListener implements EventSubscriberInterface
{
protected $mailer;
public function __construct(Mailer $mailer)
{
$this->mailer = $mailer;
}
public static function getSubscribedEvents()
{
return array(
FOSUserEvents::REGISTRATION_SUCCESS => 'onRegistrationSuccess',
);
}
public function onRegistrationSuccess(FormEvent $event)
{
$user = $event->getForm()->getData();
$this->mailer->sendWelcomeMessage($user);
$url = $this->router->generate('fos_user_security_login');
$event->setResponse(new RedirectResponse($url));
}
}
The mailer itself contains the rendering of the content of the email, also registered as a service:
mycustom_user.mailer:
class: Mycustom\UserBundle\Mailer\Mailer
arguments: ['#templating']
mycustom_user.mailer is argument for the listener. But somehow I keep getting this error:
Catchable Fatal Error: Argument 1 passed to
Mycustom\UserBundle\EventListener\RegistrationListener::__construct()
must be an instance of Mycustom\UserBundle\Mailer\Mailer, none given,
called in mycustom/app/cache/dev/appDevDebugProjectContainer.php
on line 2214 and defined in mycustom/src/Mycustom/UserBundle/EventListener/RegistrationListener.php line 19
I tried other arguments like #doctrine (and changed the listeners constructor accordingly), but I keep getting the same error. Also the #templating argument to the mailer service doesn't work.
What am I doing wrong here?
So, the problem that I had was that I had two listeners in one class. And the 2nd service definition didn't contain the argument for the constructor. Should be like this:
mycustom_user.registration_initialize:
class: Mycustom\UserBundle\EventListener\RegistrationListener
arguments: ['#mycustom_user.mailer']
tags:
- { name: kernel.event_subscriber, alias: mycustom_user_registration_listener}
mycustom_user.registration_success:
class: Mycustom\UserBundle\EventListener\RegistrationListener
arguments: ['#mycustom_user.mailer']
tags:
- { name: kernel.event_subscriber }
What is the best way to access configuration values inside an entity in a symfony 2 application?
I've searched about this and i've found two solutions:
Define the entity as a service and inject the service container to access configuration values
And this approach which defines a class in the same bundle of the entity with static methods that allows to get the parameter value
Is there any other solution? What's the best workaround?
Your entity shouldn't really access anything else, apart from associated entities. It shouldn't really have any connection outwardly to the outside world.
One way of doing what you want would be to use a subscriber or listener to listen to the entity load event and then pass that value in to the entity using the usual setter.
For example....
Your Entity
namespace Your\Bundle\Entity;
class YourClass
{
private $parameter;
public function setParameter($parameter)
{
$this->parameter = $parameter;
return $this;
}
public function getParameter()
{
return $this->parameter;
}
...
}
Your Listener
namespace Your\Bundle\EventListener;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Your\Bundle\Entity\YourEntity;
class SetParameterSubscriber implements EventSubscriber
{
protected $parameter;
public function __construct($parameter)
{
$this->parameter = $parameter;
}
public function getSubscribedEvents()
{
return array(
'postLoad',
);
}
public function postLoad(LifecycleEventArgs $args)
{
/** #var YourEntity $entity */
$entity = $args->getEntity();
// so it only does it to your YourEntity entity
if ($entity instanceof YourEntity) {
$entity->setParameter($this->parameter);
}
}
}
Your services file.
parameters:
your_bundle.subscriber.set_parameter.class:
Your\Bundle\EventListener\SetParameterSubscriber
// Should all be on one line but split for readability
services:
your_bundle.subscriber.set_parameter:
class: %your_bundle.subscriber.set_parameter.class%
arguments:
- %THE PARAMETER YOU WANT TO SET%
tags:
- { name: doctrine.event_subscriber }
You shouldn't need a configuration in your entity.
For example you have File entity and you need to save a file represented by this entity to a disk. You need some parameter, let say "upload_dir". You can pass somehow this parameter to the entity and define a method inside this entity which saves a file to upload dir. But better way would be create a service which would be responsible for saving files. Then you can inject configurtion into it and in save method pass entity object as an argument.
I have a problem injecting the EntityManger into a Symfony2 twig-extension. I did the following:
I registered a new twig extension and created a class. All of it is working.
Now I wanted to get access to the database and tried to inject the doctrine EntityManager. My first step was to add the EM as parameter to the constructor:
use XYZ\BlubBundle\Utils\SessionHelper;
class SessionHelperExtension extends \Twig_Extension
{
private $em;
private $conn;
protected $sessionHelper;
public function __construct(\Doctrine\ORM\EntityManager $em, \XYZ\BlubBundle\Utils\SessionHelper $sessionHelper) {
$this->em = $em;
$this->conn = $em->getConnection();
$this->sessionHelper = $sessionHelper;
}
[...]
}
?>
Then I added the following lines to the service.yaml:
twig.extension.sessionHelper:
class: XYZ\BlubBundle\Extensions\SessionHelperExtension
arguments: [#session_helper, #doctrine.orm.entity_manager]
tags:
- { name: twig.extension }
My own Service "sessionHelper" gets injected without a problem, but the EntityManager is always "null". What am I doing wrong here?
EDIT:
I get the following exception:
Catchable Fatal Error: Argument 2 passed to
XYZ\BlubBundle\Extensions\SessionHelperExtension::__construct() must be an instance of
Doctrine\ORM\EntityManager, none given,
called in /.../Symfony/app/cache/dev/appDevDebugProjectContainer.php on line 2918 and
defined in /.../Symfony/src/XYZ/BlubBundle/Extensions/SessionHelperExtension.php line 12
public function __construct(
\Doctrine\ORM\EntityManager $em,
\XYZ\BlubBundle\Utils\SessionHelper $sessionHelper
) {
is wrong — you need to keep the same order like in the yml:
public function __construct(
\XYZ\BlubBundle\Utils\SessionHelper $sessionHelper,
\Doctrine\ORM\EntityManager $em
) {
Update
Try this: http://www.coderelic.com/2012/06/querying-the-database-from-a-twig-extension-in-symfony-2/