ClosureTreeTest.php 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. <?php
  2. namespace Gedmo\Tree;
  3. use Doctrine\Common\EventManager;
  4. use Tool\BaseTestCaseORM;
  5. use Doctrine\Common\Util\Debug;
  6. use Tree\Fixture\Closure\Category;
  7. use Tree\Fixture\Closure\CategoryClosure;
  8. /**
  9. * These are tests for Tree behavior
  10. *
  11. * @author Gustavo Adrian <comfortablynumb84@gmail.com>
  12. * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
  13. * @package Gedmo.Tree
  14. * @link http://www.gediminasm.org
  15. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  16. */
  17. class ClosureTreeTest extends BaseTestCaseORM
  18. {
  19. const CATEGORY = "Tree\\Fixture\\Closure\\Category";
  20. const CLOSURE = "Tree\\Fixture\\Closure\\CategoryClosure";
  21. const PERSON = "Tree\\Fixture\\Closure\\Person";
  22. const USER = "Tree\\Fixture\\Closure\\User";
  23. const PERSON_CLOSURE = "Tree\\Fixture\\Closure\\PersonClosure";
  24. protected function setUp()
  25. {
  26. parent::setUp();
  27. $evm = new EventManager;
  28. $evm->addEventSubscriber(new TreeListener);
  29. $this->getMockSqliteEntityManager($evm);
  30. $this->populate();
  31. }
  32. /*public function testHeavyLoad()
  33. {
  34. $repo = $this->em->getRepository(self::CATEGORY);
  35. $parent = null;
  36. $num = 800;
  37. for($i = 0; $i < 800; $i++) {
  38. $cat = new Category;
  39. $cat->setParent($parent);
  40. $cat->setTitle('cat'.$i);
  41. $this->em->persist($cat);
  42. // siblings
  43. $rnd = rand(0, 3);
  44. for ($j = 0; $j < $rnd; $j++) {
  45. $siblingCat = new Category;
  46. $siblingCat->setTitle('cat'.$i.$j);
  47. $siblingCat->setParent($cat);
  48. $this->em->persist($siblingCat);
  49. }
  50. $num += $rnd;
  51. $parent = $cat;
  52. }
  53. $this->em->flush();
  54. var_dump('processed: '.$num);
  55. }*/
  56. public function testClosureTree()
  57. {
  58. $repo = $this->em->getRepository(self::CATEGORY);
  59. $closureRepo = $this->em->getRepository(self::CLOSURE);
  60. $food = $repo->findOneByTitle('Food');
  61. $dql = 'SELECT c FROM '.self::CLOSURE.' c';
  62. $dql .= ' WHERE c.ancestor = :ancestor';
  63. $query = $this->em->createQuery($dql);
  64. $query->setParameter('ancestor', $food);
  65. $foodClosures = $query->getResult();
  66. $this->assertEquals(12, count($foodClosures));
  67. foreach ($foodClosures as $closure) {
  68. $descendant = $closure->getDescendant();
  69. if ($descendant === $food) {
  70. $this->assertEquals(0, $closure->getDepth());
  71. continue;
  72. }
  73. $descendantTitle = $descendant->getTitle();
  74. $query->setParameter('ancestor', $descendant);
  75. $descendantClosures = $query->getResult();
  76. switch ($descendantTitle) {
  77. case 'Fruits':
  78. $this->assertEquals(5, count($descendantClosures));
  79. $this->assertEquals(1, $closure->getDepth());
  80. break;
  81. case 'Oranges':
  82. $this->assertEquals(1, count($descendantClosures));
  83. $this->assertEquals(2, $closure->getDepth());
  84. break;
  85. case 'Berries':
  86. $this->assertEquals(2, count($descendantClosures));
  87. $this->assertEquals(2, $closure->getDepth());
  88. break;
  89. case 'Vegitables':
  90. $this->assertEquals(3, count($descendantClosures));
  91. $this->assertEquals(1, $closure->getDepth());
  92. break;
  93. case 'Milk':
  94. $this->assertEquals(3, count($descendantClosures));
  95. $this->assertEquals(1, $closure->getDepth());
  96. break;
  97. case 'Cheese':
  98. $this->assertEquals(2, count($descendantClosures));
  99. $this->assertEquals(2, $closure->getDepth());
  100. break;
  101. case 'Strawberries':
  102. $this->assertEquals(1, count($descendantClosures));
  103. $this->assertEquals(3, $closure->getDepth());
  104. break;
  105. }
  106. }
  107. }
  108. public function testUpdateOfParent()
  109. {
  110. $repo = $this->em->getRepository(self::CATEGORY);
  111. $strawberries = $repo->findOneByTitle('Strawberries');
  112. $cheese = $repo->findOneByTitle('Cheese');
  113. $strawberries->setParent($cheese);
  114. $this->em->persist($strawberries);
  115. $this->em->flush();
  116. $dql = 'SELECT c FROM '.self::CLOSURE.' c';
  117. $dql .= ' WHERE c.descendant = :descendant';
  118. $query = $this->em->createQuery($dql);
  119. $query->setParameter('descendant', $strawberries);
  120. $closures = $query->getResult();
  121. $this->assertTrue($this->hasAncestor($closures, 'Cheese'));
  122. $this->assertTrue($this->hasAncestor($closures, 'Milk'));
  123. $this->assertTrue($this->hasAncestor($closures, 'Food'));
  124. $this->assertFalse($this->hasAncestor($closures, 'Berries'));
  125. $this->assertFalse($this->hasAncestor($closures, 'Fruits'));
  126. }
  127. public function testAnotherUpdateOfParent()
  128. {
  129. $repo = $this->em->getRepository(self::CATEGORY);
  130. $strawberries = $repo->findOneByTitle('Strawberries');
  131. $strawberries->setParent(null);
  132. $this->em->persist($strawberries);
  133. $this->em->flush();
  134. $dql = 'SELECT c FROM '.self::CLOSURE.' c';
  135. $dql .= ' WHERE c.descendant = :descendant';
  136. $query = $this->em->createQuery($dql);
  137. $query->setParameter('descendant', $strawberries);
  138. $closures = $query->getResult();
  139. $this->assertEquals(1, count($closures));
  140. $this->assertTrue($this->hasAncestor($closures, 'Strawberries'));
  141. }
  142. public function testBranchRemoval()
  143. {
  144. $repo = $this->em->getRepository(self::CATEGORY);
  145. $fruits = $repo->findOneByTitle('Fruits');
  146. $id = $fruits->getId();
  147. $this->em->remove($fruits);
  148. $this->em->flush();
  149. $dql = 'SELECT COUNT(c) FROM '.self::CLOSURE.' c';
  150. $dql .= ' JOIN c.descendant d';
  151. $dql .= ' JOIN c.ancestor a';
  152. $dql .= ' WHERE (a.id = :id OR d.id = :id)';
  153. $query = $this->em->createQuery($dql);
  154. $query->setParameter('id', $id);
  155. $this->assertEquals(0, $query->getSingleScalarResult());
  156. // pdo_sqlite will not cascade
  157. }
  158. /**
  159. * @expectedException Gedmo\Exception\UnexpectedValueException
  160. */
  161. public function testSettingParentToChild()
  162. {
  163. $repo = $this->em->getRepository(self::CATEGORY);
  164. $fruits = $repo->findOneByTitle('Fruits');
  165. $strawberries = $repo->findOneByTitle('Strawberries');
  166. $fruits->setParent($strawberries);
  167. $this->em->flush();
  168. }
  169. private function hasAncestor($closures, $name)
  170. {
  171. $result = false;
  172. foreach ($closures as $closure) {
  173. $ancestor = $closure->getAncestor();
  174. if ($ancestor->getTitle() === $name) {
  175. $result = true;
  176. break;
  177. }
  178. }
  179. return $result;
  180. }
  181. protected function getUsedEntityFixtures()
  182. {
  183. return array(
  184. self::CATEGORY,
  185. self::CLOSURE,
  186. self::PERSON,
  187. self::PERSON_CLOSURE,
  188. self::USER
  189. );
  190. }
  191. private function populate()
  192. {
  193. $food = new Category;
  194. $food->setTitle("Food");
  195. $this->em->persist($food);
  196. $fruits = new Category;
  197. $fruits->setTitle('Fruits');
  198. $fruits->setParent($food);
  199. $this->em->persist($fruits);
  200. $oranges = new Category;
  201. $oranges->setTitle('Oranges');
  202. $oranges->setParent($fruits);
  203. $this->em->persist($oranges);
  204. $lemons = new Category;
  205. $lemons->setTitle('Lemons');
  206. $lemons->setParent($fruits);
  207. $this->em->persist($lemons);
  208. $berries = new Category;
  209. $berries->setTitle('Berries');
  210. $berries->setParent($fruits);
  211. $this->em->persist($berries);
  212. $strawberries = new Category;
  213. $strawberries->setTitle('Strawberries');
  214. $strawberries->setParent($berries);
  215. $this->em->persist($strawberries);
  216. $vegitables = new Category;
  217. $vegitables->setTitle('Vegitables');
  218. $vegitables->setParent($food);
  219. $this->em->persist($vegitables);
  220. $cabbages = new Category;
  221. $cabbages->setTitle('Cabbages');
  222. $cabbages->setParent($vegitables);
  223. $this->em->persist($cabbages);
  224. $carrots = new Category;
  225. $carrots->setTitle('Carrots');
  226. $carrots->setParent($vegitables);
  227. $this->em->persist($carrots);
  228. $milk = new Category;
  229. $milk->setTitle('Milk');
  230. $milk->setParent($food);
  231. $this->em->persist($milk);
  232. $cheese = new Category;
  233. $cheese->setTitle('Cheese');
  234. $cheese->setParent($milk);
  235. $this->em->persist($cheese);
  236. $mouldCheese = new Category;
  237. $mouldCheese->setTitle('Mould cheese');
  238. $mouldCheese->setParent($cheese);
  239. $this->em->persist($mouldCheese);
  240. $this->em->flush();
  241. }
  242. }