3 namespace Doctrine\Tests\ORM\Functional;
4 use Doctrine\ORM\Event\PreUpdateEventArgs;
6 require_once __DIR__ . '/../../TestInit.php';
8 class LifecycleCallbackTest extends \Doctrine\Tests\OrmFunctionalTestCase
10 protected function setUp() {
13 $this->_schemaTool->createSchema(array(
14 $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\LifecycleCallbackTestEntity'),
15 $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\LifecycleCallbackTestUser'),
16 $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\LifecycleCallbackCascader'),
18 } catch (\Exception $e) {
19 // Swallow all exceptions. We do not test the schema tool here.
23 public function testPreSavePostSaveCallbacksAreInvoked()
25 $entity = new LifecycleCallbackTestEntity;
26 $entity->value = 'hello';
27 $this->_em->persist($entity);
30 $this->assertTrue($entity->prePersistCallbackInvoked);
31 $this->assertTrue($entity->postPersistCallbackInvoked);
35 $query = $this->_em->createQuery("select e from Doctrine\Tests\ORM\Functional\LifecycleCallbackTestEntity e");
36 $result = $query->getResult();
37 $this->assertTrue($result[0]->postLoadCallbackInvoked);
39 $result[0]->value = 'hello again';
43 $this->assertEquals('changed from preUpdate callback!', $result[0]->value);
46 public function testPreFlushCallbacksAreInvoked()
48 $entity = new LifecycleCallbackTestEntity;
49 $entity->value = 'hello';
50 $this->_em->persist($entity);
54 $this->assertTrue($entity->prePersistCallbackInvoked);
55 $this->assertTrue($entity->preFlushCallbackInvoked);
57 $entity->preFlushCallbackInvoked = false;
60 $this->assertTrue($entity->preFlushCallbackInvoked);
62 $entity->value = 'bye';
63 $entity->preFlushCallbackInvoked = false;
66 $this->assertTrue($entity->preFlushCallbackInvoked);
69 public function testChangesDontGetLost()
71 $user = new LifecycleCallbackTestUser;
72 $user->setName('Bob');
73 $user->setValue('value');
74 $this->_em->persist($user);
77 $user->setName('Alice');
78 $this->_em->flush(); // Triggers preUpdate
82 $user2 = $this->_em->find(get_class($user), $user->getId());
84 $this->assertEquals('Alice', $user2->getName());
85 $this->assertEquals('Hello World', $user2->getValue());
91 public function testGetReferenceWithPostLoadEventIsDelayedUntilProxyTrigger()
93 $entity = new LifecycleCallbackTestEntity;
94 $entity->value = 'hello';
95 $this->_em->persist($entity);
97 $id = $entity->getId();
101 $reference = $this->_em->getReference('Doctrine\Tests\ORM\Functional\LifecycleCallbackTestEntity', $id);
102 $this->assertFalse($reference->postLoadCallbackInvoked);
104 $reference->getValue(); // trigger proxy load
105 $this->assertTrue($reference->postLoadCallbackInvoked);
111 public function testPostLoadTriggeredOnRefresh()
113 $entity = new LifecycleCallbackTestEntity;
114 $entity->value = 'hello';
115 $this->_em->persist($entity);
117 $id = $entity->getId();
121 $reference = $this->_em->find('Doctrine\Tests\ORM\Functional\LifecycleCallbackTestEntity', $id);
122 $this->assertTrue($reference->postLoadCallbackInvoked);
123 $reference->postLoadCallbackInvoked = false;
125 $this->_em->refresh($reference);
126 $this->assertTrue($reference->postLoadCallbackInvoked, "postLoad should be invoked when refresh() is called.");
132 public function testCascadedEntitiesCallsPrePersist()
134 //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger);
136 $e1 = new LifecycleCallbackTestEntity;
137 $e2 = new LifecycleCallbackTestEntity;
139 $c = new LifecycleCallbackCascader();
140 $this->_em->persist($c);
142 $c->entities[] = $e1;
143 $c->entities[] = $e2;
147 //$this->_em->persist($c);
150 $this->assertTrue($e1->prePersistCallbackInvoked);
151 $this->assertTrue($e2->prePersistCallbackInvoked);
154 public function testLifecycleCallbacksGetInherited()
156 $childMeta = $this->_em->getClassMetadata(__NAMESPACE__ . '\LifecycleCallbackChildEntity');
157 $this->assertEquals(array('prePersist' => array(0 => 'doStuff')), $childMeta->lifecycleCallbacks);
160 public function testLifecycleListener_ChangeUpdateChangeSet()
162 $listener = new LifecycleListenerPreUpdate;
163 $this->_em->getEventManager()->addEventListener(array('preUpdate'), $listener);
165 $user = new LifecycleCallbackTestUser;
166 $user->setName('Bob');
167 $user->setValue('value');
168 $this->_em->persist($user);
172 $dql = "SELECT u FROM Doctrine\Tests\ORM\Functional\LifecycleCallbackTestUser u WHERE u.name = 'Bob'";
173 $bob = $this->_em->createQuery($dql)->getSingleResult();
174 $bob->setName('Alice');
176 $this->_em->flush(); // preUpdate reverts Alice to Bob
179 $this->_em->getEventManager()->removeEventListener(array('preUpdate'), $listener);
181 $bob = $this->_em->createQuery($dql)->getSingleResult();
183 $this->assertEquals('Bob', $bob->getName());
187 /** @Entity @HasLifecycleCallbacks */
188 class LifecycleCallbackTestUser {
189 /** @Id @Column(type="integer") @GeneratedValue */
191 /** @Column(type="string") */
193 /** @Column(type="string") */
195 public function getId() {return $this->id;}
196 public function getValue() {return $this->value;}
197 public function setValue($value) {$this->value = $value;}
198 public function getName() {return $this->name;}
199 public function setName($name) {$this->name = $name;}
201 public function testCallback() {$this->value = 'Hello World';}
206 * @HasLifecycleCallbacks
207 * @Table(name="lc_cb_test_entity")
209 class LifecycleCallbackTestEntity
212 public $prePersistCallbackInvoked = false;
213 public $postPersistCallbackInvoked = false;
214 public $postLoadCallbackInvoked = false;
216 public $preFlushCallbackInvoked = false;
219 * @Id @Column(type="integer")
220 * @GeneratedValue(strategy="AUTO")
224 * @Column(type="string", nullable=true)
229 * @ManyToOne(targetEntity="LifecycleCallbackCascader")
230 * @JoinColumn(name="cascader_id", referencedColumnName="id")
234 public function getId() {
238 public function getValue() {
243 public function doStuffOnPrePersist() {
244 $this->prePersistCallbackInvoked = true;
248 public function doStuffOnPostPersist() {
249 $this->postPersistCallbackInvoked = true;
253 public function doStuffOnPostLoad() {
254 $this->postLoadCallbackInvoked = true;
258 public function doStuffOnPreUpdate() {
259 $this->value = 'changed from preUpdate callback!';
263 public function doStuffOnPreFlush() {
264 $this->preFlushCallbackInvoked = true;
270 * @Table(name="lc_cb_test_cascade")
272 class LifecycleCallbackCascader
275 * @Id @Column(type="integer")
276 * @GeneratedValue(strategy="AUTO")
281 * @OneToMany(targetEntity="LifecycleCallbackTestEntity", mappedBy="cascader", cascade={"persist"})
285 public function __construct()
287 $this->entities = new \Doctrine\Common\Collections\ArrayCollection();
291 /** @MappedSuperclass @HasLifecycleCallbacks */
292 class LifecycleCallbackParentEntity {
299 /** @Entity @Table(name="lc_cb_childentity") */
300 class LifecycleCallbackChildEntity extends LifecycleCallbackParentEntity {
301 /** @Id @Column(type="integer") @GeneratedValue */
305 class LifecycleListenerPreUpdate
307 public function preUpdate(PreUpdateEventArgs $eventArgs)
309 $eventArgs->setNewValue('name', 'Bob');