TreeHelperTest.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. <?php
  2. namespace Tools\Test\TestCase\View\Helper;
  3. use Cake\Datasource\ConnectionManager;
  4. use Cake\ORM\Entity;
  5. use Cake\View\View;
  6. use Shim\TestSuite\TestCase;
  7. use Tools\View\Helper\TreeHelper;
  8. class TreeHelperTest extends TestCase {
  9. /**
  10. * @var array
  11. */
  12. protected $fixtures = [
  13. 'plugin.Tools.AfterTrees',
  14. ];
  15. /**
  16. * @var \Cake\ORM\Table
  17. */
  18. protected $Table;
  19. /**
  20. * @var \Tools\View\Helper\TreeHelper
  21. */
  22. protected $Tree;
  23. /**
  24. * Initial Tree
  25. *
  26. * - One
  27. * -- One-SubA
  28. * - Two
  29. * -- Two-SubA
  30. * --- Two-SubA-1
  31. * ---- Two-SubA-1-1
  32. * - Three
  33. * - Four
  34. * -- Four-SubA
  35. *
  36. * @return void
  37. */
  38. public function setUp(): void {
  39. parent::setUp();
  40. $this->Tree = new TreeHelper(new View(null));
  41. $this->Table = $this->getTableLocator()->get('AfterTrees');
  42. $this->Table->addBehavior('Tree');
  43. $connection = ConnectionManager::get('test');
  44. $sql = $this->Table->getSchema()->truncateSql($connection);
  45. foreach ($sql as $snippet) {
  46. $connection->execute($snippet);
  47. }
  48. $data = [
  49. ['name' => 'One'],
  50. ['name' => 'Two'],
  51. ['name' => 'Three'],
  52. ['name' => 'Four'],
  53. ['name' => 'One-SubA', 'parent_id' => 1],
  54. ['name' => 'Two-SubA', 'parent_id' => 2],
  55. ['name' => 'Four-SubA', 'parent_id' => 4],
  56. ['name' => 'Two-SubA-1', 'parent_id' => 6],
  57. ['name' => 'Two-SubA-1-1', 'parent_id' => 8],
  58. ];
  59. foreach ($data as $row) {
  60. $row = new Entity($row);
  61. $this->Table->save($row);
  62. }
  63. }
  64. /**
  65. * @return void
  66. */
  67. public function tearDown(): void {
  68. unset($this->Table);
  69. $this->getTableLocator()->clear();
  70. parent::tearDown();
  71. }
  72. /**
  73. * @return void
  74. */
  75. public function testGenerate() {
  76. $tree = $this->Table->find('threaded')->toArray();
  77. $output = $this->Tree->generate($tree);
  78. $expected = <<<TEXT
  79. <ul>
  80. <li>One
  81. <ul>
  82. <li>One-SubA</li>
  83. </ul>
  84. </li>
  85. <li>Two
  86. <ul>
  87. <li>Two-SubA
  88. <ul>
  89. <li>Two-SubA-1
  90. <ul>
  91. <li>Two-SubA-1-1</li>
  92. </ul>
  93. </li>
  94. </ul>
  95. </li>
  96. </ul>
  97. </li>
  98. <li>Three</li>
  99. <li>Four
  100. <ul>
  101. <li>Four-SubA</li>
  102. </ul>
  103. </li>
  104. </ul>
  105. TEXT;
  106. $this->assertTextEquals($expected, $output);
  107. $this->assertTrue(substr_count($output, '<ul>') === substr_count($output, '</ul>'));
  108. $this->assertTrue(substr_count($output, '<li>') === substr_count($output, '</li>'));
  109. }
  110. /**
  111. * @return void
  112. */
  113. public function testGenerateWithFindAll() {
  114. $tree = $this->Table->find('all', ['order' => ['lft' => 'ASC']])->toArray();
  115. $output = $this->Tree->generate($tree);
  116. $expected = <<<TEXT
  117. <ul>
  118. <li>One
  119. <ul>
  120. <li>One-SubA</li>
  121. </ul>
  122. </li>
  123. <li>Two
  124. <ul>
  125. <li>Two-SubA
  126. <ul>
  127. <li>Two-SubA-1
  128. <ul>
  129. <li>Two-SubA-1-1</li>
  130. </ul>
  131. </li>
  132. </ul>
  133. </li>
  134. </ul>
  135. </li>
  136. <li>Three</li>
  137. <li>Four
  138. <ul>
  139. <li>Four-SubA</li>
  140. </ul>
  141. </li>
  142. </ul>
  143. TEXT;
  144. $output = str_replace(["\t", "\r", "\n"], '', $output);
  145. $expected = str_replace(["\t", "\r", "\n"], '', $expected);
  146. $this->assertTextEquals($expected, $output);
  147. }
  148. /**
  149. * @return void
  150. */
  151. public function testGenerateWithDepth() {
  152. $tree = $this->Table->find('threaded')->toArray();
  153. $output = $this->Tree->generate($tree, ['depth' => 1]);
  154. $expected = <<<TEXT
  155. <ul>
  156. <li>One
  157. <ul>
  158. <li>One-SubA</li>
  159. </ul>
  160. </li>
  161. <li>Two
  162. <ul>
  163. <li>Two-SubA
  164. <ul>
  165. <li>Two-SubA-1
  166. <ul>
  167. <li>Two-SubA-1-1</li>
  168. </ul>
  169. </li>
  170. </ul>
  171. </li>
  172. </ul>
  173. </li>
  174. <li>Three</li>
  175. <li>Four
  176. <ul>
  177. <li>Four-SubA</li>
  178. </ul>
  179. </li>
  180. </ul>
  181. TEXT;
  182. $this->assertTextEquals($expected, $output);
  183. }
  184. /**
  185. * @return void
  186. */
  187. public function testGenerateWithSettings() {
  188. $tree = $this->Table->find('threaded')->toArray();
  189. $output = $this->Tree->generate($tree, ['class' => 'navi', 'id' => 'main', 'type' => 'ol']);
  190. $expected = <<<TEXT
  191. <ol class="navi" id="main">
  192. <li>One
  193. <ol>
  194. <li>One-SubA</li>
  195. </ol>
  196. </li>
  197. <li>Two
  198. <ol>
  199. <li>Two-SubA
  200. <ol>
  201. <li>Two-SubA-1
  202. <ol>
  203. <li>Two-SubA-1-1</li>
  204. </ol>
  205. </li>
  206. </ol>
  207. </li>
  208. </ol>
  209. </li>
  210. <li>Three</li>
  211. <li>Four
  212. <ol>
  213. <li>Four-SubA</li>
  214. </ol>
  215. </li>
  216. </ol>
  217. TEXT;
  218. $this->assertTextEquals($expected, $output);
  219. }
  220. /**
  221. * @return void
  222. */
  223. public function testGenerateWithMaxDepth() {
  224. $tree = $this->Table->find('threaded')->toArray();
  225. $output = $this->Tree->generate($tree, ['maxDepth' => 2]);
  226. $expected = <<<TEXT
  227. <ul>
  228. <li>One
  229. <ul>
  230. <li>One-SubA</li>
  231. </ul>
  232. </li>
  233. <li>Two
  234. <ul>
  235. <li>Two-SubA
  236. <ul>
  237. <li>Two-SubA-1</li>
  238. </ul>
  239. </li>
  240. </ul>
  241. </li>
  242. <li>Three</li>
  243. <li>Four
  244. <ul>
  245. <li>Four-SubA</li>
  246. </ul>
  247. </li>
  248. </ul>
  249. TEXT;
  250. $this->assertTextEquals($expected, $output);
  251. }
  252. /**
  253. * @return void
  254. */
  255. public function testGenerateWithAutoPath() {
  256. $tree = $this->Table->find('threaded')->toArray();
  257. $output = $this->Tree->generate($tree, ['autoPath' => [7, 10]]); // Two-SubA-1
  258. $expected = <<<TEXT
  259. <ul>
  260. <li>One
  261. <ul>
  262. <li>One-SubA</li>
  263. </ul>
  264. </li>
  265. <li class="active">Two
  266. <ul>
  267. <li class="active">Two-SubA
  268. <ul>
  269. <li class="active">Two-SubA-1
  270. <ul>
  271. <li>Two-SubA-1-1</li>
  272. </ul>
  273. </li>
  274. </ul>
  275. </li>
  276. </ul>
  277. </li>
  278. <li>Three</li>
  279. <li>Four
  280. <ul>
  281. <li>Four-SubA</li>
  282. </ul>
  283. </li>
  284. </ul>
  285. TEXT;
  286. $this->assertTextEquals($expected, $output);
  287. $output = $this->Tree->generate($tree, ['autoPath' => [8, 9]]); // Two-SubA-1-1
  288. $expected = <<<TEXT
  289. <ul>
  290. <li>One
  291. <ul>
  292. <li>One-SubA</li>
  293. </ul>
  294. </li>
  295. <li class="active">Two
  296. <ul>
  297. <li class="active">Two-SubA
  298. <ul>
  299. <li class="active">Two-SubA-1
  300. <ul>
  301. <li class="active">Two-SubA-1-1</li>
  302. </ul>
  303. </li>
  304. </ul>
  305. </li>
  306. </ul>
  307. </li>
  308. <li>Three</li>
  309. <li>Four
  310. <ul>
  311. <li>Four-SubA</li>
  312. </ul>
  313. </li>
  314. </ul>
  315. TEXT;
  316. $this->assertTextEquals($expected, $output);
  317. }
  318. /**
  319. * @return void
  320. */
  321. public function testGenerateWithAutoPathAsEntity() {
  322. $tree = $this->Table->find('threaded')->toArray();
  323. $entity = new Entity();
  324. $entity->lft = 7;
  325. $entity->rght = 10;
  326. $output = $this->Tree->generate($tree, ['autoPath' => $entity]);
  327. $expected = <<<TEXT
  328. <ul>
  329. <li>One
  330. <ul>
  331. <li>One-SubA</li>
  332. </ul>
  333. </li>
  334. <li class="active">Two
  335. <ul>
  336. <li class="active">Two-SubA
  337. <ul>
  338. <li class="active">Two-SubA-1
  339. <ul>
  340. <li>Two-SubA-1-1</li>
  341. </ul>
  342. </li>
  343. </ul>
  344. </li>
  345. </ul>
  346. </li>
  347. <li>Three</li>
  348. <li>Four
  349. <ul>
  350. <li>Four-SubA</li>
  351. </ul>
  352. </li>
  353. </ul>
  354. TEXT;
  355. $this->assertTextEquals($expected, $output);
  356. }
  357. /**
  358. * - One
  359. * -- One-SubA
  360. * - Two
  361. * -- Two-SubA
  362. * --- Two-SubA-1
  363. * ---- Two-SubA-1-1
  364. * -- Two-SubB
  365. * -- Two-SubC
  366. * - Three
  367. * - Four
  368. * -- Four-SubA
  369. *
  370. * @return void
  371. */
  372. public function testGenerateWithAutoPathAndHideUnrelated() {
  373. $data = [
  374. ['name' => 'Two-SubB', 'parent_id' => 2],
  375. ['name' => 'Two-SubC', 'parent_id' => 2],
  376. ];
  377. foreach ($data as $row) {
  378. $row = new Entity($row);
  379. $this->Table->save($row);
  380. }
  381. $tree = $this->Table->find('threaded')->toArray();
  382. $id = 6;
  383. $nodes = $this->Table->find('path', ['for' => $id]);
  384. $path = $nodes->extract('id')->toArray();
  385. $output = $this->Tree->generate($tree, ['autoPath' => [6, 11], 'hideUnrelated' => true, 'treePath' => $path, 'callback' => [$this, '_myCallback']]); // Two-SubA
  386. $expected = <<<TEXT
  387. <ul>
  388. <li>One</li>
  389. <li class="active">Two (active)
  390. <ul>
  391. <li class="active">Two-SubA (active)
  392. <ul>
  393. <li>Two-SubA-1</li>
  394. </ul>
  395. </li>
  396. <li>Two-SubB</li>
  397. <li>Two-SubC</li>
  398. </ul>
  399. </li>
  400. <li>Three</li>
  401. <li>Four</li>
  402. </ul>
  403. TEXT;
  404. $output = str_replace(["\t"], '', $output);
  405. $expected = str_replace(["\t"], '', $expected);
  406. $this->assertTextEquals($expected, $output);
  407. }
  408. /**
  409. * - One
  410. * -- One-SubA
  411. * - Two
  412. * -- Two-SubA
  413. * --- Two-SubA-1
  414. * ---- Two-SubA-1-1
  415. * -- Two-SubB
  416. * -- Two-SubC
  417. * - Three
  418. * - Four
  419. * -- Four-SubA
  420. *
  421. * @return void
  422. */
  423. public function testGenerateWithAutoPathAndHideUnrelatedAndSiblings() {
  424. $data = [
  425. ['name' => 'Two-SubB', 'parent_id' => 2],
  426. ['name' => 'Two-SubC', 'parent_id' => 2],
  427. ];
  428. foreach ($data as $row) {
  429. $row = new Entity($row);
  430. $this->Table->save($row);
  431. }
  432. $tree = $this->Table->find('threaded')->toArray();
  433. $id = 6; // Two-SubA
  434. $nodes = $this->Table->find('path', ['for' => $id]);
  435. $path = $nodes->extract('id')->toArray();
  436. $output = $this->Tree->generate($tree, [
  437. 'autoPath' => [6, 11], 'hideUnrelated' => true, 'treePath' => $path,
  438. 'callback' => [$this, '_myCallbackSiblings']]);
  439. $expected = <<<TEXT
  440. <ul>
  441. <li>One (sibling)</li>
  442. <li class="active">Two (active)
  443. <ul>
  444. <li class="active">Two-SubA (active)
  445. <ul>
  446. <li>Two-SubA-1</li>
  447. </ul>
  448. </li>
  449. <li>Two-SubB</li>
  450. <li>Two-SubC</li>
  451. </ul>
  452. </li>
  453. <li>Three (sibling)</li>
  454. <li>Four (sibling)</li>
  455. </ul>
  456. TEXT;
  457. $output = str_replace(["\t", "\r", "\n"], '', $output);
  458. $expected = str_replace(["\t", "\r", "\n"], '', $expected);
  459. $this->assertTextEquals($expected, $output);
  460. }
  461. /**
  462. * @param array $data
  463. * @return string|null
  464. */
  465. public function _myCallback(array $data) {
  466. /** @var \Cake\ORM\Entity $entity */
  467. $entity = $data['data'];
  468. if (!empty($entity['hide'])) {
  469. return null;
  470. }
  471. return $data['data']['name'] . ($data['activePathElement'] ? ' (active)' : '');
  472. }
  473. /**
  474. * @param array $data
  475. * @return string|null
  476. */
  477. public function _myCallbackSiblings(array $data) {
  478. /** @var \Cake\ORM\Entity $entity */
  479. $entity = $data['data'];
  480. if (!empty($entity['hide'])) {
  481. return null;
  482. }
  483. if ($data['depth'] == 0 && $data['isSibling']) {
  484. return $entity['name'] . ' (sibling)';
  485. }
  486. return $entity['name'] . ($data['activePathElement'] ? ' (active)' : '');
  487. }
  488. /**
  489. * @return void
  490. */
  491. public function testGenerateProductive() {
  492. $tree = $this->Table->find('threaded')->toArray();
  493. $output = $this->Tree->generate($tree, ['indent' => false]);
  494. $expected = '<ul><li>One<ul><li>One-SubA</li></ul></li><li>Two<ul><li>Two-SubA<ul><li>Two-SubA-1<ul><li>Two-SubA-1-1</li></ul></li></ul></li></ul></li><li>Three</li><li>Four<ul><li>Four-SubA</li></ul></li></ul>';
  495. $this->assertTextEquals($expected, $output);
  496. }
  497. /**
  498. * @return void
  499. */
  500. public function testGenerateWithEntityUsage() {
  501. $data = [
  502. ['name' => 'Two-SubB', 'parent_id' => 2],
  503. ['name' => 'Two-SubC', 'parent_id' => 2],
  504. ];
  505. foreach ($data as $row) {
  506. $row = new Entity($row);
  507. $this->Table->save($row);
  508. }
  509. $tree = $this->Table->find('threaded')->toArray();
  510. $id = 6;
  511. $nodes = $this->Table->find('path', ['for' => $id]);
  512. $path = $nodes->extract('id')->toArray();
  513. $output = $this->Tree->generate($tree, [
  514. 'autoPath' => [6, 11], 'treePath' => $path,
  515. 'callback' => [$this, '_myCallbackEntity']]); // Two-SubA
  516. $expected = <<<TEXT
  517. <ul>
  518. <li>One
  519. <ul>
  520. <li>One-SubA</li>
  521. </ul>
  522. </li>
  523. <li class="active">Two (active)
  524. <ul>
  525. <li class="active">Two-SubA (active)
  526. <ul>
  527. <li>Two-SubA-1
  528. <ul>
  529. <li>Two-SubA-1-1</li>
  530. </ul>
  531. </li>
  532. </ul>
  533. </li>
  534. <li>Two-SubB</li>
  535. <li>Two-SubC</li>
  536. </ul>
  537. </li>
  538. <li>Three</li>
  539. <li>Four
  540. <ul>
  541. <li>Four-SubA</li>
  542. </ul>
  543. </li>
  544. </ul>
  545. TEXT;
  546. $output = str_replace(["\t", "\r", "\n"], '', $output);
  547. $expected = str_replace(["\t", "\r", "\n"], '', $expected);
  548. $this->assertTextEquals($expected, $output);
  549. }
  550. /**
  551. * @param array $data
  552. * @return string|null
  553. */
  554. public function _myCallbackEntity(array $data) {
  555. /** @var \Cake\ORM\Entity $entity */
  556. $entity = $data['data'];
  557. return h($entity->name) . ($data['activePathElement'] ? ' (active)' : '');
  558. }
  559. }