I have the entity (such as below). I want to set some default values while creating. As you can see in __construct
, it is easy to set the $name
(string), but how can I set the $group
? (for example I know that there is a group in database with id=122
)
/**
* @ORM\Entity
*/
class Person {
private $id;
/** @ORM\Column(type="string") */
private $name;
/**
* @ORM\ManyToOne(targetEntity="Group", inversedBy="persons")
* @ORM\JoinColumn(referencedColumnName="id")
*/
private $group;
public function setGroup(Group $group)
{
$this->group = $group;
$group->addPerson($this);
}
// ... setters/getters
//construct default Person
public function __construct()
{
$this->setName("Mike");
$this->setGroup($EXISTING_GROUP_FROM_MY_DB); // <<--------------
}
}
I agree with moonwave99 that this is poor design. Here you are trying to access the database (through the Doctrine service) from a place that is not container-aware (i.e. it does not, and should not, know about Doctrine).
I had a similar issue recently... pretty much the same exact issue, actually. But I didn't want this logic to be inside the controller. So I wrote a service to take care of the User creation. And I gave that service access to the only other service it needed: Doctrine.
Here's an example, where a User is created with all available Roles:
namespace MyBundle\Entity;
class UserFactory
{
private $doctrine;
public function __construct($doctrine)
{
$this->doctrine = $doctrine;
}
public function generateNewUser($email, $password)
{
$user = new User();
// Since you have access to the Doctrine service, you can use $this->doctrine
// to do anything you would normally do in your controller with $this->getDoctrine()
$roles = $this->doctrine->getEntityManager()->getRepository("MyBundle:Role")->findAll();
foreach ($roles as $role)
{
$user->addRole($role);
}
return $user;
}
}
Now register that service in config.yml
or services.yml
, remembering to pass the Doctrine service to it:
services:
mybundle.factory.user:
class: MyBundle\Entity\UserFactory
arguments: ['@doctrine']
And that's it... Now, in your controller, you can create a new User by doing:
public function MyController()
{
$user = $this->get("mybundle.factory.user")->generateNewUser("someone@email.com", "password123");
}
Another method is to use either Lifecycle Callbacks in the entity or an Event Listener to do more complex functionality.
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 = self::DEFAULT_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()->find('MyBundle:Group', $this->group ?: self::DEFAULT_GROUP);
$this->setGroup($group);
}
}
}
Now when you persist a Person entity it will add the group if it was not explicitly set in the controller.
$person = new Person;
echo $person->getName(); //outputs: Mike
$person->setName('Foo Bar');
$em->persist($person); //persist or do nothing if already persisted
$group = $person->getGroup();
$groupPerson = $group->getPerson();
echo $group->getId(); //outputs: 122
echo $groupPerson->getName(); //outputs: Foo Bar
$em->flush(); //save to database
For sanity here are the links to the docs for the doctrine events: