PrePersit current user - php

[SETTINGS]
Symfony 3.4
Logged user (FosUserBundle)
Projet Entity (below)
src/AppBundle/Entity/Projet.php
class Projet {
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="titre", type="string", length=50)
*/
private $titre;
/**
* #var \DateTime
*
* #ORM\Column(name="creation", type="datetime")
*/
private $creation;
/**
* #var \DateTime
*
* #ORM\Column(name="modification", type="datetime")
*/
private $modification;
/**
* #var
*
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\User", inversedBy="projet")
* #ORM\JoinColumn(nullable=false)
*/
private $user;
/**
* #ORM\PrePersist
* #ORM\PreUpdate
*/
public function updatedTimestamps() {
$this->setModification(new \DateTime());
if($this->getCreation() == null) {
$this->setCreation(new \DateTime());
$this->setSupprime(false);
}
}
}
[PROBLEM]
As is, I'm setting creation and modification on PrePersit/PreUpdate.
I would like to also set the id of the current logged user, how can I do it?

To do this, you need to have access to the security.token_storage service and call $tokenStorage->getToken()->getUser() to retrieve the current user. Since it is not really recommended to inject a service into an entity, you should create an entity listener as described in this section of the doctrine documentation.
Then, by declaring your entity listener as a service and adding the security.token_storage to its constructor arguments like this (in your services.yml):
listener.projet:
class: AppBundle\Listener\ProjetListener
arguments: [ "#security.token_storage" ]
tags:
- { name: doctrine.orm.entity_listener, lazy: true }
You would be able to access the currently logged in user inside your prePersist and preUpdate methods.
Edit: Here is how your listener should look like
AppBundle/Listener/ProjetListener.php
namespace AppBundle\Listener;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use AppBundle\Entity\Projet;
class ProjetListener
{
private $tokenStorage;
public function __construct(TokenStorage $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
public function prePersist(Projet $projet, LifecycleEventArgs $args)
{
// Assigning the current user to the Projet instance being persisted
$projet->setUser($this->tokenStorage->getToken()->getUser());
/* .. other actions of prePersist .. */
}
public function preUpdate(Projet $projet, PreUpdateEventArgs $args)
{
/* .. actions of preUpdate .. */
}
}

I think you have to do this in a subscriber, listening on prepersist and preupdate doctrine event.
You will be able to get the currentn user by injecting the security.token_storage service

Related

Symfony doctrine many to many unique

I have to entity with manyToMany relation, that i have transform in two OneToMany. So I have create an other Entity called CollanaCollezionista into that i have some attribute.
I want that the couple collana/collezionista is unique, how can i do this on doctrine and symfony?
/**
* Collana
*/
class Collana
{
private $id;
private $titolo;
/**
* #MaxDepth(1)
* #ORM\OneToMany(targetEntity="CollezionistaCollana", mappedBy="collana")
*/
private $collezionisti;
}
/**
* Collezionista
*/
class Collezionista
{
private $id;
private $user;
/**
* #ORM\OneToMany(targetEntity="CollezionistaCollana", mappedBy="collezionista")
*/
private $collane;
}
So I have an other entity, called CollezionistaCollana. How can i set that the couple collezionista-collana is unique?
Answer:
#UniqueConstraint do the stuff.
use Doctrine\ORM\Mapping\UniqueConstraint as UniqueConstraint;
/**
* CollezionistaCollana
*
* #ORM\Table(name="collezionista_collana",uniqueConstraints={#‌UniqueConstraint(nam‌​e="unique_hold", columns={"idCollezionista", "idCollana"})})
* #ORM\Entity
*/
class CollezionistaCollana
{
// Class details
}

PersistentCollection not initialized but data in database with Symfony and Doctrine

I have a problem with a PersistentCollection.
I have an Object User (herited of FOSUserbundle user class) who have an EmdebedDocument Seance. The Seance have an Array of Event.
My Seance Class:
/**
* #MongoDB\EmbeddedDocument
*/
class Seance
{
/**
* #MongoDB\Id
*/
protected $id;
/**
* #MongoDB\EmbedMany(targetDocument="Event")
*/
protected $dispos ;
/**
* #MongoDB\Field(type="string")
*/
protected $rayonDeplacement;
/**
* #MongoDB\Field(type="string")
*/
protected $lieu;
/**
* #MongoDB\Field(type="string")
*/
protected $prix;
/**
* #MongoDB\Field(type="string")
*/
protected $nbPersonne;
And my class Event
/**
* #MongoDB\EmbeddedDocument
*/
class Event extends BaseEvent
{
/**
* #var integer
* #MongoDB\Id
*/
protected $id;
/**
* #var \DateTime
* #MongoDB\Field(type="date")
* #Assert\NotNull()
*/
protected $startDate;
/**
* #var \DateTime
* #MongoDB\Field(type="date")
* #Assert\NotNull()
*/
protected $endDate;
I give the event from user with:
$user->getSeance()->getDispos()
This function returns a empty PersistentCollection while they are events in database.
When dump the return of getDispos() method I have:
I dont't understant why I have mongoData field with my data but arrayCollection empty.
Thank you for yout help.
PersistentCollection is initialized lazily - for performance reasons, the data from database is held in mongoData. The collection is initialized during the first time you need some data from it (or try to modify it) - then the data held in mongoData is hydrated into your embedded documents and that is added to decorated coll. All this is happening transparently to you, just try using your collection instead of dumping it.

Notification system in symfony 3.1

I use symfony 3.1. I want to create a notification system in my application in symfony. I have created an entity named notification to save notifications. So when a user creates, edits or removes a record in the database, I want to save this action in a notification table. I used HasLifecycleCallbacks() annotation method and it forced me to create a controller object in my entity but nothing has worked. How can i do it? Is there another solution?
/**
* #ORM\Table(name="user")
* #ORM\Entity(repositoryClass="CM\UserBundle\Repository\UserRepository")
* #ORM\HasLifecycleCallbacks()
*/
class User extends BaseUser {
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="nom", type="string", unique=true, length=255, nullable=true)
* #Assert\NotBlank()
*/
protected $nom;
/**
* #var int
*
* #ORM\Column(name="numero", type="integer", unique=true, nullable=true)
* #Assert\NotBlank()
*/
protected $numero;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set nom
*
* #param string $nom
*
* #return User
*/
public function setNom($nom)
{
$this->nom = $nom;
return $this;
}
/**
* Get nom
*
* #return string
*/
public function getNom()
{
return $this->nom;
}
/**
* Set numero
*
* #param integer $numero
*
* #return User
*/
public function setNumero($numero)
{
$this->numero = $numero;
return $this;
}
/**
* Get numero
*
* #return int
*/
public function getNumero()
{
return $this->numero;
}
/**
* #ORM\PreRemove
*/
public function notify(){
$controlleur = new RemoveController();
$em = $controlleur->getDoctrine()->getManager();
$notif = new Notification();
$notif->setOperation('recording');
$notif->setUser('William');
$em->persist($notif);
$em->flush();
}
}
I've resolved my problem. I had not read very well the documentation. And then i did some more research. So here is a solution that works for me in symfony 3.1.
I used dependency injection. I have injected ManagerRegistry to have the entity manager service and TokenStorage for tokenStorage service to know the current user connected.
I have created a folder name NotificationDB. And then i have also created a class name NotificationDB.php which here is the code. For this example, i suppose that i have a form to register a foo entity.
namespace CM\GestionBundle\NotificationBD;
use Doctrine\Common\Persistence\ManagerRegistry;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use \CM\GestionBundle\Entity\Notification;
class NotificationBD {
private $managerRegistry;
/**
* #var TokenStorage
*/
private $tokenStorage;
public function __construct(ManagerRegistry $managerRegistry, TokenStorage $tokenStorage)
{
$this->managerRegistry = $managerRegistry;
$this->tokenStorage = $tokenStorage;
}
public function notifyEvent(){
$entityManager = $this->managerRegistry->getManager();
$user = $this->tokenStorage->getToken()->getUser();
$notif = new Notification();
$notif->setDateNotif(new \Datetime());
$notif->setUser($user);
$notif->setActionNotif('recording');
$notif->setObjetNotif('foo');
$entityManager->persist($notifEdition);
$entityManager->flush();
}
}
In CM\GestionBundle\Resources\config**, i have configure as service in **services.yml file which here is the content :
CM_gestion.notification:
class: CM\GestionBundle\NotificationBD\NotificationBD
arguments: ['#doctrine', '#security.token_storage']
And then i have created a listener for which will call this service. For this example, i will create a foo entity listener which will listen register event and use the service to persist the notification entity. Here is my foo listener.
namespace CM\GestionBundle\DoctrineListener;
use CM\GestionBundle\NotificationBD\NotificationBD;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use \CM\GestionBundle\Entity\Foo;
class FooListener {
/**
* #var NotificationBD
*/
private $notificationBD;
public function __construct(NotificationBD $notificationBD) {
$this->notificationBD = $notificationBD;
}
public function postPersist(LifecycleEventArgs $args) {
$entity = $args->getObject();
if (!$entity instanceof Foo) {
return;
}
$this->notificationBD->notifyEvent();
}
}
In CM\GestionBundle\Resources\config
The last thing to do is to add this listener in services.yml file. Here is the content
CM_gestion.doctrine_listener.foo:
class: CM\GestionBundle\DoctrineListener\FooListener
arguments:
- "#CM_gestion.notification"
tags:
- {name: doctrine.event_listener, event: postPersist}
That all. this solution work for me in symfony 3.1. This problem can be marked as resolved. Thank

Gedmo Timestampable Annotation Doesn't Appear to Work With Event Listeners

So,
I have an Entity set up with Timestampable fields, like so:
<?php
namespace Acme\Bundle\Entity;
use Acme\PathEnumerableInterface as EnumerableInterface;
use Acme\PathEnumerable as PathEnumerableTrait;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* SomeEntity
*
* #ORM\Table()
* #ORM\HasLifecycleCallbacks
*/
class SomeEntity implements EnumerableInterface
{
use PathEnumerableTrait;
/**
* #var \DateTime
*
* #Gedmo\Timestampable(on="create")
* #ORM\Column(name="created_at", type="datetime")
*/
private $createdAt;
/**
* #var \DateTime
*
* #ORM\Column(name="updated_at", type="datetime")
* #Gedmo\Timestampable(on="update")
*/
private $updatedAt;
/**
* Get createdAt
*
* #return \DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* Get updatedAt
*
* #return \DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
}
I have then set up a lifecycle subscriber for postPersist, postUpdate, and postFlush events. The service.yml looks like this:
services:
acme.element_listener:
class: %iacme.element_listener.class%
arguments:
manager: "#doctrine.orm.default_entity_manager"
tags:
- { name: doctrine.event_subscriber, connection: default }
The actual listener looks like this:
<?php
namespace Acme\Bundle\EventListener;
use Acme\PathEnumerableInterface;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Event\PostFlushEventArgs;
class EventListener
{
/**
* #var Doctrine\ORM\EntityManager
*/
private $entityManager;
/**
* #var array
*/
private $paths = [];
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function getSubscribedEvents()
{
return ['postPersist'];
}
private function postPersist(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
// Set $newPath to a generated path and check so we don't end up in an infinite loop
if ($entity->getPath() != $newPath) {
//... Do some stuff with the entity
$this->entityManager->persist($entity);
$this->entityManager->flush();
}
}
}
When I remove the event listener, everything is fine and the timestampable fields are filled in correctly. However, when I create a new entity with the listener enabled timestampable fields aren't filled out.
My question is, then, what would cause the event listener to stop Gedmo filling in the timestampable fields? I'm probably doing something really silly, but as yet I can't see what that might be...
Ok, so there were a couple of things wrong here that were causing me issues:
My EventListener Class didn't implement EventSubscriber. The class should have been declared like so:
<?php
namespace Acme\Bundle\EventListener;
use Acme\PathEnumerableInterface;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Event\PostFlushEventArgs;
use Doctrine\Common\EventSubscriber;
class EventListener implements EventSubscriber
{
// .....
}
You can't pass the EntityManager as a construct argument. This actually makes quite a bit of sense when you think about it, and doesn't really hinder what I do as the getEntityManager event is available in the LifecycleEventArgs object and the PostFlushEventArgs object

Symfony2 : Entities not created in database

I'm making entities with Symfony2 and Doctrine2. I made some entities that represent a many-to-many relation between two of my entities.
An example of one of these entities :
/**
* #ORM\Entity
*/
class Contact_Conference_Invitation
{
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Aurae\UserBundle\Entity\Contact")
*/
private $contact;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Aurae\ConferenceBundle\Entity\Conference")
*/
private $conference;
/**
* #var datetime dateInvitation
*
* #ORM\Column(name="dateInvitation", type="datetime")
*/
private $dateInvitation;
//Getters and setters
}
I have tried updating my sql schema, but the tables corresponding to these entities do not appear. Is there somewhere I have to declare them (config or such)? If not, what's wrong?
Thanks a lot
Edit : I had forgotten the namespace for these class, and that's why they were omitted by Doctrine. Another case closed :) thanks for the answers!
Assumptions ...
No, you don't need to declare them anywhere else than in your Entity directory.
What's the error message you got?
I guess you added
use Doctrine\ORM\Mapping as ORM;
on the top of your classes to let them be mapped.
I tried ...
I tried to generate your entities by adding a simple Contact & Conference entities and it's working fine.
Here are the code snippets:
Contact_Conference_Invitation.php
namespace Ahsio\StackBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class Contact_Conference_Invitation
{
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Ahsio\StackBundle\Entity\Contact")
*/
private $contact;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Ahsio\StackBundle\Entity\Conference")
*/
private $conference;
/**
* #var datetime dateInvitation
*
* #ORM\Column(name="dateInvitation", type="datetime")
*/
private $dateInvitation;
//Getters and setters
}
Contact.php
namespace Ahsio\StackBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class Contact
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #param $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
}
Conference.php
namespace Ahsio\StackBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class Conference
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #param $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
}
Here are the generated tables:
NB: I used a specific namespace for the entities generation to work fine, you need to change them.
Also don't forget to check that you have automapping enabled.
In your config.yml you should have
doctrine:
orm:
auto_mapping: true
Came across this question because my entities weren't generated as well, this was my issue, it could save some time to people struggling with the same issue.
I don't see the definition of your ManyToMany relation in the sample of code you provided.
As an example, here's a ManyToMany relationship I implemented for a project
Entity Project.php
/**
* #var Provider[]
*
* #ORM\ManyToMany(targetEntity="Provider", mappedBy="projects")
*/
protected $providers = null;
Entity Provider.php
/**
* #var Project[]
*
* #ORM\ManyToMany(targetEntity="Project", inversedBy="providers")
* #ORM\JoinTable(name="PROVIDER_PROJECT")
*/
protected $projects = null;
As you can see, here you define the join table for your ManyToMany relationship.
Of course those entities are specific for my particular project but you get the idea and you can adapt it easily for your needs.

Categories