New to symfony2 and Doctrine.
How can I set a default value to the field foo_id
(which is a reference on Foo
table) to point on the ID 1
of the Foo table (which exists in all cases) ?
MeNavigationBundleEntityPublicText: type: entity table: public_text id: id: type: integer id: true generator: strategy: AUTO fields: title: type: string length: '255' nullable: false content: type: string length: '2000' nullable: false manyToOne: foo: #How to set a default value??? targetEntity: MeNavigationBundleEntityFoo joinColumn: name: foo_id referencedColumnName: id nullable: false lifecycleCallbacks: { }
I tried a lot of things without success :
- Set default value to ID 1 in the constructor of Foo
- Perform a request to retrieve the Foo object of ID 1 in the Me entity (could works, but bad practice)
Advertisement
Answer
Please note that using columnDefinition
alone will work for generating migrations but will break the ORM context and potentially cause FK integrity issues. You will still need to add the object association to the ORM for persisting entities. See warnings from Ocramius
Example:
(new PublicText()) ->getFoo(); //null - expected object(Foo)#1 (1) { ["id"] => int(1) }
I have seen many ways to achieve this in doctrine 2.
Constructor
In general, the quickest way and what most users do is require an association in the constructor.
public function __construct(Foo $foo) { $this->foo = $foo; }
Then you can use getReference
to retrieve it in your controller without needing to query the database. See http://doctrine-orm.readthedocs.org/en/latest/reference/advanced-configuration.html#reference-proxies
$foo = $em->getReference('app:Foo', 1); $text = new PathToEntityPublicText($foo); $em->persist($text); $em->flush();
LifeCycleEvents
My preferred way Another method to set the default value with most ManyToOne
relationships is to utilize the LifeCycleEvents
http://doctrine-orm.readthedocs.org/en/latest/reference/events.html
Though it does have some caveats to be aware of. So be sure to RTM before implementing into production environments. In this case it should work fine, but I don’t know your entire mapping structure.
use DoctrineORMEventLifecycleEventArgs; /** * @Entity * @HasLifeCycleEvents */ class PublicText { // ... /** * @PrePersist * @param DoctrineORMEventLifecycleEventArgs $event */ public function onPrePersist(LifecycleEventArgs $event) { if (false === empty($this->foo)) { return; } $this->foo = $event->getEntityManager()->getReference('app:Foo', 1); } }
Then in your controller.
$text = new PathToEntityPublicText; $em->persist($text); //retrieve and set foo if not set in the Entity Event. $em->flush();
Repository Method
Another option within your Entity is to just set the property’s value using a Repository.
Define Repository Class in Entity
/** * @Entity(repositoryClass="PublicTextRepo") */ class PublicText { // ... }
Repository
use DoctrineORMEntityRepository; class PublicTextRepo extends EntityRepository { public function create() { $text = new PathToEntityPublicText; $foo = $this->_em->getReference('app:Foo', 1); $text->setFoo($foo ); return $text; } }
Then in your controller you can then do
$text = $em->getRepository('app:PublicText')->create(); $em->persist($text); $em->flush();
Discriminator Map
Though not always viable depending on the use case. One of the ways I go about defining a default value of an Entity is creating a DiscriminatorMap
with single table inheritance. http://doctrine-orm.readthedocs.org/en/latest/reference/inheritance-mapping.html#single-table-inheritance.
This way when the object is created the default value is automatically set in the database, and locks the object as that type. The issue is that the resulting value is not an object like it is in the other methods above.
To get the object’s discriminator static
value, you can use constants within the objects you define.
/** * @Entity * @InheritanceType("SINGLE_TABLE") * @Table(name="user") * @DiscriminatorColumn(name="type", type="string") * @DiscriminatorMap({Person::TYPE="Person", Employee::TYPE="Employee"}) */ class Person { const TYPE = 'person'; /** * @return string [person|employee] */ public function getType() { return $this::TYPE; } // ... } /** * @Entity */ class Employee extends Person { const TYPE = 'employee'; // ... }
Then all you need to do in your controller is.
$employee = new PathToEntityEmployee; $em->persist($employee); //inserts with `user.type` as `employee` $em->flush(); echo $employee->getType(); //employee