The recommended method is to require the associated Entity object within the constructor arguments, optionally in combination with a Factory such as the Entity Repository, to supply the Group Entity during instantiation. This ensures the entity is always in a valid state.
src/Entity/Person.php
namespace App\Entity; /** * @ORM\Entity(repositoryClass="App\Repository\PersonRepository") */ class Person { //... public function __construct($name, Group $group) { $this->setName($name); $this->setGroup($group); } //... }
src/Repsotory/PersonRepository.php
namespace App\Repsotory; use App\Entity\Group; use App\Entity\Person; class PersonRepository { const DEFAULT_GROUP = 122; public function create($name, Group $group = null) { if (null === $group) { $group = $this->_em->getReference(Group::class, self::DEFAULT_GROUP); } $person = new Person($name, $group); $this->_em->persist($person); return $person; } }
This allows you to rely solely on the Doctrine ORM Entity Manager to maintain the default Group association.
$person = $em->getRepository(Person::class)->create('Mike'); $group = $person->getGroup(); echo $group->getId(); //outputs: 122 $em->flush();
This approach can be extended upon in Symfony to use Query services instead of the doctrine entity repository, to provide a central location that handles the instantiation of the entities.
In Symfony 3.4+ you can use Repository services to provide dependency injection for the repository, instead of using the EntityManagerInterface.
src/Service/PersonCreateQuery.php
namespace App\Service; use App\Entity\Group; use App\Entity\Person; use Doctrine\ORM\EntityManagerInterface; class PersonCreateQuery { private $em; public function __construct(EntityManagerInterface $em) { $this->em = $em; } public function __invoke($name) { $group = $this->em->getReference(Group::class, 122); $person = new Person($name, $group); $this->em->persist($person); return $person; } }
Now you can use dependency injection to retrieve the Query service and use it as desired, such as with a Symfony Form or Controller.
namespace App\Controller; use App\Service\PersonCreateQuery; class PersonController { public function createAction(PersonCreateQuery $query) { $person = $query('Mike'); $this->getDoctrine()->getManager()->flush(); //... } }
Note: Usages of $em->getReference() can be replaced with $em->find(). Using $em->getReference() will prevent a query to the database but will throw an exception if the reference is invalid, while using $em->find() will return null instead.
Another approach is to use either Lifecycle Callbacks in the entity or an Event Listener to do more complex functionality. However, this will cause your entity to be instantiated in an invalid state until it is persisted.
use Doctrine\ORM\Event\LifecycleEventArgs; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\HasLifecycleCallbacks */ class Person { const DEFAULT_GROUP = 122; /** @ORM\Column(type="string") */ private $name = 'Mike'; /** * @ORM\ManyToOne(targetEntity="Group", inversedBy="persons") * @ORM\JoinColumn(referencedColumnName="id") */ private $group; //.... public function setGroup(Group $group) { $this->group = $group; $group->addPerson($this); } /** * @param LifecycleEventArgs $event * @ORM\PrePersist */ public function onPrePersist(LifecycleEventArgs $event) { if (!$this->group instanceof Group) { /** set default group if not specified */ $group = $event->getEntityManager()->getReference(Group::class, self::DEFAULT_GROUP); $this->setGroup($group); } } }
Now when you persist a Person entity it will add the group if it was not explicitly set elsewhere.
$person = new Person(); $person->setName('Foo Bar'); $em->persist($person); //persist or do nothing if already persisted $group = $person->getGroup(); echo $group->getId(); //outputs: 122 $groupPerson = $group->getPerson(); echo $groupPerson->getName(); //outputs: Foo Bar $em->flush(); //save to database
For sanity here are the links to the docs for the doctrine events: