LifecycleCallbackTest.php 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. <?php
  2. namespace Doctrine\Tests\ORM\Functional;
  3. use Doctrine\ORM\Event\PreUpdateEventArgs;
  4. require_once __DIR__ . '/../../TestInit.php';
  5. class LifecycleCallbackTest extends \Doctrine\Tests\OrmFunctionalTestCase
  6. {
  7. protected function setUp() {
  8. parent::setUp();
  9. try {
  10. $this->_schemaTool->createSchema(array(
  11. $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\LifecycleCallbackTestEntity'),
  12. $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\LifecycleCallbackTestUser'),
  13. $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\LifecycleCallbackCascader'),
  14. ));
  15. } catch (\Exception $e) {
  16. // Swallow all exceptions. We do not test the schema tool here.
  17. }
  18. }
  19. public function testPreSavePostSaveCallbacksAreInvoked()
  20. {
  21. $entity = new LifecycleCallbackTestEntity;
  22. $entity->value = 'hello';
  23. $this->_em->persist($entity);
  24. $this->_em->flush();
  25. $this->assertTrue($entity->prePersistCallbackInvoked);
  26. $this->assertTrue($entity->postPersistCallbackInvoked);
  27. $this->_em->clear();
  28. $query = $this->_em->createQuery("select e from Doctrine\Tests\ORM\Functional\LifecycleCallbackTestEntity e");
  29. $result = $query->getResult();
  30. $this->assertTrue($result[0]->postLoadCallbackInvoked);
  31. $result[0]->value = 'hello again';
  32. $this->_em->flush();
  33. $this->assertEquals('changed from preUpdate callback!', $result[0]->value);
  34. }
  35. public function testChangesDontGetLost()
  36. {
  37. $user = new LifecycleCallbackTestUser;
  38. $user->setName('Bob');
  39. $user->setValue('value');
  40. $this->_em->persist($user);
  41. $this->_em->flush();
  42. $user->setName('Alice');
  43. $this->_em->flush(); // Triggers preUpdate
  44. $this->_em->clear();
  45. $user2 = $this->_em->find(get_class($user), $user->getId());
  46. $this->assertEquals('Alice', $user2->getName());
  47. $this->assertEquals('Hello World', $user2->getValue());
  48. }
  49. /**
  50. * @group DDC-194
  51. */
  52. public function testGetReferenceWithPostLoadEventIsDelayedUntilProxyTrigger()
  53. {
  54. $entity = new LifecycleCallbackTestEntity;
  55. $entity->value = 'hello';
  56. $this->_em->persist($entity);
  57. $this->_em->flush();
  58. $id = $entity->getId();
  59. $this->_em->clear();
  60. $reference = $this->_em->getReference('Doctrine\Tests\ORM\Functional\LifecycleCallbackTestEntity', $id);
  61. $this->assertFalse($reference->postLoadCallbackInvoked);
  62. $reference->getId(); // trigger proxy load
  63. $this->assertTrue($reference->postLoadCallbackInvoked);
  64. }
  65. /**
  66. * @group DDC-958
  67. */
  68. public function testPostLoadTriggeredOnRefresh()
  69. {
  70. $entity = new LifecycleCallbackTestEntity;
  71. $entity->value = 'hello';
  72. $this->_em->persist($entity);
  73. $this->_em->flush();
  74. $id = $entity->getId();
  75. $this->_em->clear();
  76. $reference = $this->_em->find('Doctrine\Tests\ORM\Functional\LifecycleCallbackTestEntity', $id);
  77. $this->assertTrue($reference->postLoadCallbackInvoked);
  78. $reference->postLoadCallbackInvoked = false;
  79. $this->_em->refresh($reference);
  80. $this->assertTrue($reference->postLoadCallbackInvoked, "postLoad should be invoked when refresh() is called.");
  81. }
  82. /**
  83. * @group DDC-113
  84. */
  85. public function testCascadedEntitiesCallsPrePersist()
  86. {
  87. //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger);
  88. $e1 = new LifecycleCallbackTestEntity;
  89. $e2 = new LifecycleCallbackTestEntity;
  90. $c = new LifecycleCallbackCascader();
  91. $this->_em->persist($c);
  92. $c->entities[] = $e1;
  93. $c->entities[] = $e2;
  94. $e1->cascader = $c;
  95. $e2->cascader = $c;
  96. //$this->_em->persist($c);
  97. $this->_em->flush();
  98. $this->assertTrue($e1->prePersistCallbackInvoked);
  99. $this->assertTrue($e2->prePersistCallbackInvoked);
  100. }
  101. public function testLifecycleCallbacksGetInherited()
  102. {
  103. $childMeta = $this->_em->getClassMetadata(__NAMESPACE__ . '\LifecycleCallbackChildEntity');
  104. $this->assertEquals(array('prePersist' => array(0 => 'doStuff')), $childMeta->lifecycleCallbacks);
  105. }
  106. public function testLifecycleListener_ChangeUpdateChangeSet()
  107. {
  108. $listener = new LifecycleListenerPreUpdate;
  109. $this->_em->getEventManager()->addEventListener(array('preUpdate'), $listener);
  110. $user = new LifecycleCallbackTestUser;
  111. $user->setName('Bob');
  112. $user->setValue('value');
  113. $this->_em->persist($user);
  114. $this->_em->flush();
  115. $this->_em->clear();
  116. $dql = "SELECT u FROM Doctrine\Tests\ORM\Functional\LifecycleCallbackTestUser u WHERE u.name = 'Bob'";
  117. $bob = $this->_em->createQuery($dql)->getSingleResult();
  118. $bob->setName('Alice');
  119. $this->_em->flush(); // preUpdate reverts Alice to Bob
  120. $this->_em->clear();
  121. $this->_em->getEventManager()->removeEventListener(array('preUpdate'), $listener);
  122. $bob = $this->_em->createQuery($dql)->getSingleResult();
  123. $this->assertEquals('Bob', $bob->getName());
  124. }
  125. }
  126. /** @Entity @HasLifecycleCallbacks */
  127. class LifecycleCallbackTestUser {
  128. /** @Id @Column(type="integer") @GeneratedValue */
  129. private $id;
  130. /** @Column(type="string") */
  131. private $value;
  132. /** @Column(type="string") */
  133. private $name;
  134. public function getId() {return $this->id;}
  135. public function getValue() {return $this->value;}
  136. public function setValue($value) {$this->value = $value;}
  137. public function getName() {return $this->name;}
  138. public function setName($name) {$this->name = $name;}
  139. /** @PreUpdate */
  140. public function testCallback() {$this->value = 'Hello World';}
  141. }
  142. /**
  143. * @Entity
  144. * @HasLifecycleCallbacks
  145. * @Table(name="lc_cb_test_entity")
  146. */
  147. class LifecycleCallbackTestEntity
  148. {
  149. /* test stuff */
  150. public $prePersistCallbackInvoked = false;
  151. public $postPersistCallbackInvoked = false;
  152. public $postLoadCallbackInvoked = false;
  153. /**
  154. * @Id @Column(type="integer")
  155. * @GeneratedValue(strategy="AUTO")
  156. */
  157. private $id;
  158. /**
  159. * @Column(type="string", nullable=true)
  160. */
  161. public $value;
  162. /**
  163. * @ManyToOne(targetEntity="LifecycleCallbackCascader")
  164. * @JoinColumn(name="cascader_id", referencedColumnName="id")
  165. */
  166. public $cascader;
  167. public function getId() {
  168. return $this->id;
  169. }
  170. /** @PrePersist */
  171. public function doStuffOnPrePersist() {
  172. $this->prePersistCallbackInvoked = true;
  173. }
  174. /** @PostPersist */
  175. public function doStuffOnPostPersist() {
  176. $this->postPersistCallbackInvoked = true;
  177. }
  178. /** @PostLoad */
  179. public function doStuffOnPostLoad() {
  180. $this->postLoadCallbackInvoked = true;
  181. }
  182. /** @PreUpdate */
  183. public function doStuffOnPreUpdate() {
  184. $this->value = 'changed from preUpdate callback!';
  185. }
  186. }
  187. /**
  188. * @Entity
  189. * @Table(name="lc_cb_test_cascade")
  190. */
  191. class LifecycleCallbackCascader
  192. {
  193. /**
  194. * @Id @Column(type="integer")
  195. * @GeneratedValue(strategy="AUTO")
  196. */
  197. private $id;
  198. /**
  199. * @OneToMany(targetEntity="LifecycleCallbackTestEntity", mappedBy="cascader", cascade={"persist"})
  200. */
  201. public $entities;
  202. public function __construct()
  203. {
  204. $this->entities = new \Doctrine\Common\Collections\ArrayCollection();
  205. }
  206. }
  207. /** @MappedSuperclass @HasLifecycleCallbacks */
  208. class LifecycleCallbackParentEntity {
  209. /** @PrePersist */
  210. function doStuff() {
  211. }
  212. }
  213. /** @Entity @Table(name="lc_cb_childentity") */
  214. class LifecycleCallbackChildEntity extends LifecycleCallbackParentEntity {
  215. /** @Id @Column(type="integer") @GeneratedValue */
  216. private $id;
  217. }
  218. class LifecycleListenerPreUpdate
  219. {
  220. public function preUpdate(PreUpdateEventArgs $eventArgs)
  221. {
  222. $eventArgs->setNewValue('name', 'Bob');
  223. }
  224. }