TYPO3 CMS  TYPO3_8-7
RelationTest.php
Go to the documentation of this file.
1 <?php
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
29 
30 class RelationTest extends \TYPO3\TestingFramework\Core\Functional\FunctionalTestCase
31 {
35  protected $blog;
36 
40  protected $persistentManager;
41 
42  protected $testExtensionsToLoad = ['typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example'];
43 
44  protected $coreExtensionsToLoad = ['extbase', 'fluid'];
45 
49  protected $objectManager;
50 
54  protected function setUp()
55  {
56  parent::setUp();
57 
58  $this->importDataSet('PACKAGE:typo3/testing-framework/Resources/Core/Functional/Fixtures/pages.xml');
59  $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/blogs.xml');
60  $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/posts.xml');
61  $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/persons.xml');
62  $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/tags.xml');
63  $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/tags-mm.xml');
64  $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/post-tag-mm.xml');
65  $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/categories.xml');
66  $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/category-mm.xml');
67 
68  $this->objectManager = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class);
69  $this->persistentManager = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager::class);
70  /* @var $blogRepository \TYPO3\CMS\Extbase\Persistence\Repository */
71  $blogRepository = $this->objectManager->get(BlogRepository::class);
72  $this->blog = $blogRepository->findByUid(1);
73  }
74 
80  public function attachPostToBlogAtTheEnd()
81  {
82  $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_blogexample_domain_model_post');
83  $queryBuilder->getRestrictions()->removeAll();
84  $countPostsOriginal = $queryBuilder
85  ->count('*')
86  ->from('tx_blogexample_domain_model_post')
87  ->where(
88  $queryBuilder->expr()->eq(
89  'blog',
90  $queryBuilder->createNamedParameter($this->blog->getUid(), \PDO::PARAM_INT)
91  )
92  )->execute()
93  ->fetchColumn(0);
94 
95  $newPostTitle = 'sdufhisdhuf';
97  $newPost = $this->objectManager->get(Post::class);
98  $newPost->setBlog($this->blog);
99  $newPost->setTitle($newPostTitle);
100  $newPost->setContent('Bla Bla Bla');
101 
102  $this->blog->addPost($newPost);
103  $this->updateAndPersistBlog();
104 
105  $queryBuilder->resetQueryParts();
106  $countPosts = $queryBuilder
107  ->count('*')
108  ->from('tx_blogexample_domain_model_post')
109  ->where(
110  $queryBuilder->expr()->eq(
111  'blog',
112  $queryBuilder->createNamedParameter($this->blog->getUid(), \PDO::PARAM_INT)
113  )
114  )->execute()
115  ->fetchColumn(0);
116  $this->assertEquals($countPostsOriginal + 1, $countPosts);
117 
118  $queryBuilder->resetQueryParts();
119  $post = $queryBuilder
120  ->select('title', 'sorting')
121  ->from('tx_blogexample_domain_model_post')
122  ->where(
123  $queryBuilder->expr()->eq(
124  'blog',
125  $queryBuilder->createNamedParameter($this->blog->getUid(), \PDO::PARAM_INT)
126  )
127  )->orderBy('sorting', 'DESC')
128  ->execute()
129  ->fetch();
130  $this->assertSame($newPostTitle, $post['title']);
131  $this->assertEquals($countPostsOriginal + 1, $post['sorting']);
132  }
133 
139  public function removeLastPostFromBlog()
140  {
141  $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_blogexample_domain_model_post');
142  $queryBuilder->getRestrictions()
143  ->removeAll()->add(new DeletedRestriction());
144  $countPostsOriginal = $queryBuilder
145  ->count('*')
146  ->from('tx_blogexample_domain_model_post')
147  ->execute()
148  ->fetchColumn(0);
149 
150  $queryBuilder->resetQueryParts();
151  $post = $queryBuilder
152  ->select('title', 'sorting')
153  ->from('tx_blogexample_domain_model_post')
154  ->where(
155  $queryBuilder->expr()->eq(
156  'blog',
157  $queryBuilder->createNamedParameter($this->blog->getUid(), \PDO::PARAM_INT)
158  )
159  )->orderBy('sorting', 'DESC')
160  ->execute()
161  ->fetch();
162  $this->assertEquals(10, $post['sorting']);
163 
164  $posts = $this->blog->getPosts();
165  $postsArray = $posts->toArray();
166  $latestPost = array_pop($postsArray);
167 
168  $this->assertEquals(10, $latestPost->getUid());
169 
170  $this->blog->removePost($latestPost);
171  $this->updateAndPersistBlog();
172 
173  $queryBuilder->resetQueryParts();
174  $countPosts = $queryBuilder
175  ->count('*')
176  ->from('tx_blogexample_domain_model_post')
177  ->execute()
178  ->fetchColumn(0);
179  $this->assertEquals(($countPostsOriginal - 1), $countPosts);
180 
181  $queryBuilder->resetQueryParts();
182  $post = $queryBuilder
183  ->select('title', 'sorting')
184  ->from('tx_blogexample_domain_model_post')
185  ->where(
186  $queryBuilder->expr()->eq(
187  'uid',
188  $queryBuilder->createNamedParameter($latestPost->getUid(), \PDO::PARAM_INT)
189  )
190  )->orderBy('sorting', 'DESC')
191  ->execute()
192  ->fetch();
193  $this->assertNull($post['uid']);
194 
195  $queryBuilder->resetQueryParts();
196  $post = $queryBuilder
197  ->select('title', 'sorting')
198  ->from('tx_blogexample_domain_model_post')
199  ->where(
200  $queryBuilder->expr()->eq(
201  'blog',
202  $queryBuilder->createNamedParameter($this->blog->getUid(), \PDO::PARAM_INT)
203  )
204  )->orderBy('sorting', 'DESC')
205  ->execute()
206  ->fetch();
207  $this->assertSame('Post9', $post['title']);
208  $this->assertEquals(9, $post['sorting']);
209  }
210 
216  public function addPostToBlogInTheMiddle()
217  {
218  $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_blogexample_domain_model_post');
219  $queryBuilder->getRestrictions()
220  ->removeAll()->add(new DeletedRestriction());
221  $countPostsOriginal = $queryBuilder
222  ->count('*')
223  ->from('tx_blogexample_domain_model_post')
224  ->execute()
225  ->fetchColumn(0);
226 
228  $newPost = $this->objectManager->get(Post::class);
229 
230  $posts = clone $this->blog->getPosts();
231  $this->blog->getPosts()->removeAll($posts);
232  $counter = 1;
233  $newPostTitle = 'INSERTED POST at position 6';
234  foreach ($posts as $post) {
235  $this->blog->addPost($post);
236  if ($counter === 5) {
237  $newPost->setBlog($this->blog);
238  $newPost->setTitle($newPostTitle);
239  $newPost->setContent('Bla Bla Bla');
240  $this->blog->addPost($newPost);
241  }
242  $counter++;
243  }
244  $this->updateAndPersistBlog();
245 
246  $queryBuilder->resetQueryParts();
247  $countPosts = $queryBuilder
248  ->count('*')
249  ->from('tx_blogexample_domain_model_post')
250  ->execute()
251  ->fetchColumn(0);
252  $this->assertEquals($countPostsOriginal + 1, $countPosts);
253 
254  //last post
255  $queryBuilder->resetQueryParts();
256  $post = $queryBuilder
257  ->select('title', 'sorting')
258  ->from('tx_blogexample_domain_model_post')
259  ->where(
260  $queryBuilder->expr()->eq(
261  'blog',
262  $queryBuilder->createNamedParameter($this->blog->getUid(), \PDO::PARAM_INT)
263  )
264  )->orderBy('sorting', 'DESC')
265  ->execute()
266  ->fetch();
267  $this->assertSame('Post10', $post['title']);
268  $this->assertEquals(11, $post['sorting']);
269 
270  // check sorting of the post added in the middle
271  $queryBuilder->resetQueryParts();
272  $post = $queryBuilder
273  ->select('title', 'sorting')
274  ->from('tx_blogexample_domain_model_post')
275  ->where(
276  $queryBuilder->expr()->eq(
277  'uid',
278  $queryBuilder->createNamedParameter($newPost->getUid(), \PDO::PARAM_INT)
279  )
280  )->orderBy('sorting', 'DESC')
281  ->execute()
282  ->fetch();
283  $this->assertSame($newPostTitle, $post['title']);
284  $this->assertEquals(6, $post['sorting']);
285  }
286 
292  public function removeMiddlePostFromBlog()
293  {
294  $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_blogexample_domain_model_post');
295  $queryBuilder->getRestrictions()
296  ->removeAll()->add(new DeletedRestriction());
297  $countPostsOriginal = $queryBuilder
298  ->count('*')
299  ->from('tx_blogexample_domain_model_post')
300  ->execute()
301  ->fetchColumn(0);
302 
303  $posts = clone $this->blog->getPosts();
304  $counter = 1;
305  foreach ($posts as $post) {
306  if ($counter === 5) {
307  $this->blog->removePost($post);
308  }
309  $counter++;
310  }
311  $this->updateAndPersistBlog();
312 
313  $queryBuilder->resetQueryParts();
314  $countPosts = $queryBuilder
315  ->count('*')
316  ->from('tx_blogexample_domain_model_post')
317  ->execute()
318  ->fetchColumn(0);
319  $this->assertEquals($countPostsOriginal - 1, $countPosts);
320 
321  $queryBuilder->resetQueryParts();
322  $post = $queryBuilder
323  ->select('title', 'sorting')
324  ->from('tx_blogexample_domain_model_post')
325  ->where(
326  $queryBuilder->expr()->eq(
327  'blog',
328  $queryBuilder->createNamedParameter($this->blog->getUid(), \PDO::PARAM_INT)
329  )
330  )->orderBy('sorting', 'DESC')
331  ->execute()
332  ->fetch();
333  $this->assertSame('Post10', $post['title']);
334  $this->assertEquals(10, $post['sorting']);
335  }
336 
342  public function movePostFromEndToTheMiddle()
343  {
344  $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_blogexample_domain_model_post');
345  $queryBuilder->getRestrictions()
346  ->removeAll()->add(new DeletedRestriction());
347  $countPostsOriginal = $queryBuilder
348  ->count('*')
349  ->from('tx_blogexample_domain_model_post')
350  ->execute()
351  ->fetchColumn(0);
352 
353  $posts = clone $this->blog->getPosts();
354  $postsArray = $posts->toArray();
355  $latestPost = array_pop($postsArray);
356 
357  $this->blog->getPosts()->removeAll($posts);
358  $counter = 0;
359  $postCount = $posts->count();
360  foreach ($posts as $post) {
361  if ($counter !== ($postCount - 1)) {
362  $this->blog->addPost($post);
363  }
364  if ($counter === 4) {
365  $latestPost->setTitle('MOVED POST ' . $latestPost->getTitle());
366  $this->blog->addPost($latestPost);
367  }
368  $counter++;
369  }
370  $this->updateAndPersistBlog();
371 
372  $queryBuilder->resetQueryParts();
373  $countPosts = $queryBuilder
374  ->count('*')
375  ->from('tx_blogexample_domain_model_post')
376  ->execute()
377  ->fetchColumn(0);
378  $this->assertEquals($countPostsOriginal, $countPosts);
379 
380  $queryBuilder->getRestrictions()->removeAll();
381  $post = $queryBuilder
382  ->select('title', 'sorting')
383  ->from('tx_blogexample_domain_model_post')
384  ->where(
385  $queryBuilder->expr()->eq(
386  'blog',
387  $queryBuilder->createNamedParameter($this->blog->getUid(), \PDO::PARAM_INT)
388  )
389  )->orderBy('sorting', 'DESC')
390  ->execute()
391  ->fetch();
392  $this->assertSame('Post9', $post['title']);
393  $this->assertEquals(10, $post['sorting']);
394 
395  $queryBuilder->resetQueryParts();
396  $post = $queryBuilder
397  ->select('title', 'uid')
398  ->from('tx_blogexample_domain_model_post')
399  ->where(
400  $queryBuilder->expr()->andX(
401  $queryBuilder->expr()->eq(
402  'blog',
403  $queryBuilder->createNamedParameter($this->blog->getUid(), \PDO::PARAM_INT)
404  ),
405  $queryBuilder->expr()->eq('sorting', $queryBuilder->createNamedParameter(6, \PDO::PARAM_INT))
406  )
407  )
408  ->execute()
409  ->fetch();
410  $this->assertSame('MOVED POST Post10', $post['title']);
411  $this->assertEquals(10, $post['uid']);
412  }
413 
419  public function attachTagToPostAtTheEnd()
420  {
421  $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_blogexample_domain_model_tag');
422  $queryBuilder->getRestrictions()
423  ->removeAll();
424  $countOriginal = $queryBuilder
425  ->count('*')
426  ->from('tx_blogexample_domain_model_tag')
427  ->execute()
428  ->fetchColumn(0);
429 
430  $newTagTitle = 'sdufhisdhuf';
431 
433  $newTag = $this->objectManager->get('ExtbaseTeam\\BlogExample\\Domain\\Model\\Tag', $newTagTitle);
434 
436  $postRepository = $this->objectManager->get(PostRepository::class);
437  $post = $postRepository->findByUid(1);
438  $post->addTag($newTag);
439 
440  $postRepository->update($post);
441  $this->persistentManager->persistAll();
442 
443  $queryBuilder->resetQueryParts();
444  $count = $queryBuilder
445  ->count('*')
446  ->from('tx_blogexample_domain_model_tag')
447  ->execute()
448  ->fetchColumn(0);
449  $this->assertEquals($countOriginal + 1, $count);
450 
451  $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_blogexample_post_tag_mm');
452  $queryBuilder->getRestrictions()
453  ->removeAll();
454  $tag = $queryBuilder
455  ->select('uid_foreign')
456  ->from('tx_blogexample_post_tag_mm')
457  ->where(
458  $queryBuilder->expr()->eq(
459  'uid_local',
460  $queryBuilder->createNamedParameter($post->getUid(), \PDO::PARAM_INT)
461  )
462  )->orderBy('sorting', 'DESC')
463  ->execute()
464  ->fetch();
465  $this->assertEquals($newTag->getUid(), $tag['uid_foreign']);
466  }
467 
473  public function removeLastTagFromPost()
474  {
475  $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_blogexample_domain_model_tag');
476  $queryBuilder->getRestrictions()
477  ->removeAll()->add(new DeletedRestriction());
478  $countOriginal = $queryBuilder
479  ->count('*')
480  ->from('tx_blogexample_domain_model_tag')
481  ->execute()
482  ->fetchColumn(0);
483 
485  $postRepository = $this->objectManager->get(PostRepository::class);
486  $post = $postRepository->findByUid(1);
487  $tags = $post->getTags();
488  $tagsArray = $tags->toArray();
489  $latestTag = array_pop($tagsArray);
490 
491  $this->assertEquals(10, $latestTag->getUid());
492 
493  $post->removeTag($latestTag);
494 
495  $postRepository->update($post);
496  $this->persistentManager->persistAll();
497 
498  $queryBuilder->resetQueryParts();
499  $countTags = $queryBuilder
500  ->count('*')
501  ->from('tx_blogexample_domain_model_tag')
502  ->execute()
503  ->fetchColumn(0);
504  $this->assertEquals($countOriginal, $countTags);
505 
506  $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_blogexample_post_tag_mm');
507  $queryBuilder->getRestrictions()
508  ->removeAll();
509  $tag = $queryBuilder
510  ->select('uid_foreign')
511  ->from('tx_blogexample_post_tag_mm')
512  ->where(
513  $queryBuilder->expr()->eq(
514  'uid_local',
515  $queryBuilder->createNamedParameter($post->getUid(), \PDO::PARAM_INT)
516  )
517  )->orderBy('sorting', 'DESC')
518  ->execute()
519  ->fetch();
520  $this->assertEquals(9, $tag['uid_foreign']);
521 
522  $queryBuilder->resetQueryParts();
523  $tag = $queryBuilder
524  ->select('uid_foreign')
525  ->from('tx_blogexample_post_tag_mm')
526  ->where(
527  $queryBuilder->expr()->andX(
528  $queryBuilder->expr()->eq(
529  'uid_local',
530  $queryBuilder->createNamedParameter($post->getUid(), \PDO::PARAM_INT)
531  ),
532  $queryBuilder->expr()->eq(
533  'uid_foreign',
534  $queryBuilder->createNamedParameter($latestTag->getUid(), \PDO::PARAM_INT)
535  )
536  )
537  )->orderBy('sorting', 'DESC')
538  ->execute()
539  ->fetch();
540  $this->assertNull($tag['uid_foreign']);
541  }
542 
548  public function addTagToPostInTheMiddle()
549  {
550  $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_blogexample_post_tag_mm');
551  $queryBuilder->getRestrictions()
552  ->removeAll();
553  $countTagsOriginal = $queryBuilder
554  ->count('*')
555  ->from('tx_blogexample_post_tag_mm')
556  ->where(
557  $queryBuilder->expr()->eq('uid_local', $queryBuilder->createNamedParameter(1, \PDO::PARAM_INT))
558  )
559  ->execute()
560  ->fetchColumn(0);
561 
563  $postRepository = $this->objectManager->get(PostRepository::class);
564  $post = $postRepository->findByUid(1);
565  $tags = clone $post->getTags();
566  $post->setTags(new ObjectStorage());
567 
569  $newTag = $this->objectManager->get(Tag::class, 'INSERTED TAG at position 6 : ' . strftime(''));
570 
571  $counter = 1;
572  foreach ($tags as $tag) {
573  $post->addTag($tag);
574  if ($counter === 5) {
575  $post->addTag($newTag);
576  }
577  $counter++;
578  }
579 
580  $postRepository->update($post);
581  $this->persistentManager->persistAll();
582 
583  $queryBuilder->resetQueryParts();
584  $countTags = $queryBuilder
585  ->count('*')
586  ->from('tx_blogexample_post_tag_mm')
587  ->where(
588  $queryBuilder->expr()->eq('uid_local', $queryBuilder->createNamedParameter(1, \PDO::PARAM_INT))
589  )
590  ->execute()
591  ->fetchColumn(0);
592  $this->assertEquals($countTagsOriginal + 1, $countTags);
593 
594  $queryBuilder->resetQueryParts();
595  $tag = $queryBuilder
596  ->select('uid_foreign')
597  ->from('tx_blogexample_post_tag_mm')
598  ->where(
599  $queryBuilder->expr()->eq(
600  'uid_local',
601  $queryBuilder->createNamedParameter($post->getUid(), \PDO::PARAM_INT)
602  )
603  )->orderBy('sorting', 'DESC')
604  ->execute()
605  ->fetch();
606  $this->assertEquals(10, $tag['uid_foreign']);
607 
608  $queryBuilder->resetQueryParts();
609  $tag = $queryBuilder
610  ->select('uid_foreign')
611  ->from('tx_blogexample_post_tag_mm')
612  ->where(
613  $queryBuilder->expr()->andX(
614  $queryBuilder->expr()->eq(
615  'uid_local',
616  $queryBuilder->createNamedParameter($post->getUid(), \PDO::PARAM_INT)
617  ),
618  $queryBuilder->expr()->eq('sorting', $queryBuilder->createNamedParameter(6, \PDO::PARAM_INT))
619  )
620  )->orderBy('sorting', 'DESC')
621  ->execute()
622  ->fetch();
623  $this->assertEquals($newTag->getUid(), $tag['uid_foreign']);
624  }
625 
631  public function removeMiddleTagFromPost()
632  {
633  $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_blogexample_post_tag_mm');
634  $queryBuilder->getRestrictions()
635  ->removeAll();
636  $countTags = $queryBuilder
637  ->count('*')
638  ->from('tx_blogexample_post_tag_mm')
639  ->where(
640  $queryBuilder->expr()->eq('uid_local', $queryBuilder->createNamedParameter(1, \PDO::PARAM_INT))
641  )
642  ->execute()
643  ->fetchColumn(0);
644  $this->assertEquals(10, $countTags);
645 
647  $postRepository = $this->objectManager->get(PostRepository::class);
648  $post = $postRepository->findByUid(1);
649  $tags = clone $post->getTags();
650  $counter = 1;
651  foreach ($tags as $tag) {
652  if ($counter === 5) {
653  $post->removeTag($tag);
654  }
655  $counter++;
656  }
657 
658  $postRepository->update($post);
659  $this->persistentManager->persistAll();
660 
661  $queryBuilder->resetQueryParts();
662  $countTags = $queryBuilder
663  ->count('*')
664  ->from('tx_blogexample_post_tag_mm')
665  ->where(
666  $queryBuilder->expr()->eq('uid_local', $queryBuilder->createNamedParameter(1, \PDO::PARAM_INT))
667  )
668  ->execute()
669  ->fetchColumn(0);
670  $this->assertEquals(9, $countTags);
671 
672  $queryBuilder->resetQueryParts();
673  $tag = $queryBuilder
674  ->select('uid_foreign', 'sorting')
675  ->from('tx_blogexample_post_tag_mm')
676  ->where(
677  $queryBuilder->expr()->eq(
678  'uid_local',
679  $queryBuilder->createNamedParameter($post->getUid(), \PDO::PARAM_INT)
680  )
681  )->orderBy('sorting', 'DESC')
682  ->execute()
683  ->fetch();
684  $this->assertEquals(10, $tag['uid_foreign']);
685  $this->assertEquals(10, $tag['sorting']);
686 
687  $queryBuilder->resetQueryParts();
688  $tag = $queryBuilder
689  ->select('uid_foreign')
690  ->from('tx_blogexample_post_tag_mm')
691  ->where(
692  $queryBuilder->expr()->andX(
693  $queryBuilder->expr()->eq(
694  'uid_local',
695  $queryBuilder->createNamedParameter($post->getUid(), \PDO::PARAM_INT)
696  ),
697  $queryBuilder->expr()->eq('sorting', $queryBuilder->createNamedParameter(5, \PDO::PARAM_INT))
698  )
699  )
700  ->execute()
701  ->fetch();
702  $this->assertNull($tag['uid_foreign']);
703  }
704 
710  public function moveTagFromEndToTheMiddle()
711  {
712  $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_blogexample_post_tag_mm');
713  $queryBuilder->getRestrictions()
714  ->removeAll();
715  $countTags = $queryBuilder
716  ->count('*')
717  ->from('tx_blogexample_post_tag_mm')
718  ->where(
719  $queryBuilder->expr()->eq('uid_local', $queryBuilder->createNamedParameter(1, \PDO::PARAM_INT))
720  )
721  ->execute()
722  ->fetchColumn(0);
723  $this->assertEquals(10, $countTags);
724 
726  $postRepository = $this->objectManager->get(PostRepository::class);
727  $post = $postRepository->findByUid(1);
728  $tags = clone $post->getTags();
729  $tagsArray = $tags->toArray();
730  $latestTag = array_pop($tagsArray);
731  $post->removeTag($latestTag);
732  $post->setTags(new ObjectStorage());
733 
734  $counter = 1;
735  $tagCount = $tags->count();
736  foreach ($tags as $tag) {
737  if ($counter !== $tagCount) {
738  $post->addTag($tag);
739  }
740  if ($counter === 5) {
741  $post->addTag($latestTag);
742  }
743  $counter++;
744  }
745  $post->addTag($latestTag);
746 
747  $postRepository->update($post);
748  $this->persistentManager->persistAll();
749 
750  $queryBuilder->resetQueryParts();
751  $countTags = $queryBuilder
752  ->count('*')
753  ->from('tx_blogexample_post_tag_mm')
754  ->where(
755  $queryBuilder->expr()->eq('uid_local', $queryBuilder->createNamedParameter(1, \PDO::PARAM_INT))
756  )
757  ->execute()
758  ->fetchColumn(0);
759  $this->assertEquals(10, $countTags);
760 
761  $queryBuilder->resetQueryParts();
762  $tag = $queryBuilder
763  ->select('uid_foreign', 'sorting')
764  ->from('tx_blogexample_post_tag_mm')
765  ->where(
766  $queryBuilder->expr()->eq(
767  'uid_local',
768  $queryBuilder->createNamedParameter($post->getUid(), \PDO::PARAM_INT)
769  )
770  )->orderBy('sorting', 'DESC')
771  ->execute()
772  ->fetch();
773  $this->assertEquals(9, $tag['uid_foreign']);
774  $this->assertEquals(10, $tag['sorting']);
775 
776  $sorting = '6';
777  $queryBuilder->resetQueryParts();
778  $tag = $queryBuilder
779  ->select('uid_foreign')
780  ->from('tx_blogexample_post_tag_mm')
781  ->where(
782  $queryBuilder->expr()->andX(
783  $queryBuilder->expr()->eq(
784  'uid_local',
785  $queryBuilder->createNamedParameter($post->getUid(), \PDO::PARAM_INT)
786  ),
787  $queryBuilder->expr()->eq(
788  'sorting',
789  $queryBuilder->createNamedParameter($sorting, \PDO::PARAM_STR)
790  )
791  )
792  )
793  ->execute()
794  ->fetch();
795  $this->assertEquals(10, $tag['uid_foreign']);
796  }
797 
803  public function timestampFieldIsUpdatedOnPostSave()
804  {
805  $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_blogexample_domain_model_post');
806  $queryBuilder->getRestrictions()
807  ->removeAll();
808  $rawPost = $queryBuilder
809  ->select('*')
810  ->from('tx_blogexample_domain_model_post')
811  ->where(
812  $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter(1, \PDO::PARAM_INT))
813  )
814  ->execute()
815  ->fetch();
816 
818  $postRepository = $this->objectManager->get(PostRepository::class);
819  $post = $postRepository->findByUid(1);
820  $post->setTitle('newTitle');
821 
822  $postRepository->update($post);
823  $this->persistentManager->persistAll();
824 
825  $queryBuilder->resetQueryParts();
826  $rawPost2 = $queryBuilder
827  ->select('*')
828  ->from('tx_blogexample_domain_model_post')
829  ->where(
830  $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter(1, \PDO::PARAM_INT))
831  )
832  ->execute()
833  ->fetch();
834  $this->assertTrue($rawPost2['tstamp'] > $rawPost['tstamp']);
835  }
836 
842  public function mmRelationWithoutMatchFieldIsResolved()
843  {
845  $postRepository = $this->objectManager->get(PostRepository::class);
846  $posts = $postRepository->findByTagAndBlog('Tag2', $this->blog);
847  $this->assertCount(1, $posts);
848  }
849 
853  public function mmRelationWithMatchFieldIsResolvedFromLocalSide()
854  {
855  $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('sys_category_record_mm');
856  $queryBuilder->getRestrictions()
857  ->removeAll();
858  $countCategories = $queryBuilder
859  ->count('*')
860  ->from('sys_category_record_mm')
861  ->where(
862  $queryBuilder->expr()->andX(
863  $queryBuilder->expr()->eq('uid_foreign', $queryBuilder->createNamedParameter(1, \PDO::PARAM_INT)),
864  $queryBuilder->expr()->eq(
865  'tablenames',
866  $queryBuilder->createNamedParameter('tx_blogexample_domain_model_post', \PDO::PARAM_STR)
867  ),
868  $queryBuilder->expr()->eq(
869  'fieldname',
870  $queryBuilder->createNamedParameter('categories', \PDO::PARAM_STR)
871  )
872  )
873  )
874  ->execute()
875  ->fetchColumn(0);
876  $this->assertEquals(3, $countCategories);
877 
879  $postRepository = $this->objectManager->get(PostRepository::class);
880  $post = $postRepository->findByUid(1);
881  $this->assertSame(3, count($post->getCategories()));
882  }
883 
889  public function mmRelationWithMatchFieldIsResolvedFromForeignSide()
890  {
892  $postRepository = $this->objectManager->get(PostRepository::class);
893  $posts = $postRepository->findByCategory(1);
894  $this->assertSame(2, count($posts));
895 
896  $posts = $postRepository->findByCategory(4);
897  $this->assertSame(0, count($posts));
898  }
899 
903  public function mmRelationWithMatchFieldIsCreatedFromLocalSide()
904  {
905  $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('sys_category_record_mm');
906  $queryBuilder->getRestrictions()
907  ->removeAll();
908  $countCategories = $queryBuilder
909  ->count('*')
910  ->from('sys_category_record_mm')
911  ->where(
912  $queryBuilder->expr()->andX(
913  $queryBuilder->expr()->eq('uid_foreign', $queryBuilder->createNamedParameter(1, \PDO::PARAM_INT)),
914  $queryBuilder->expr()->eq(
915  'tablenames',
916  $queryBuilder->createNamedParameter('tx_blogexample_domain_model_post', \PDO::PARAM_STR)
917  ),
918  $queryBuilder->expr()->eq(
919  'fieldname',
920  $queryBuilder->createNamedParameter('categories', \PDO::PARAM_STR)
921  )
922  )
923  )
924  ->execute()
925  ->fetchColumn(0);
926  $this->assertEquals(3, $countCategories);
927 
929  $postRepository = $this->objectManager->get(PostRepository::class);
930  $post = $postRepository->findByUid(1);
931 
933  $newCategory = $this->objectManager->get(\TYPO3\CMS\Extbase\Domain\Model\Category::class);
934  $newCategory->setTitle('New Category');
935 
936  $post->addCategory($newCategory);
937 
938  $postRepository->update($post);
939  $this->persistentManager->persistAll();
940 
941  $queryBuilder->resetQueryParts();
942  $countCategories = $queryBuilder
943  ->count('*')
944  ->from('sys_category_record_mm')
945  ->where(
946  $queryBuilder->expr()->andX(
947  $queryBuilder->expr()->eq('uid_foreign', $queryBuilder->createNamedParameter(1, \PDO::PARAM_INT)),
948  $queryBuilder->expr()->eq(
949  'tablenames',
950  $queryBuilder->createNamedParameter('tx_blogexample_domain_model_post', \PDO::PARAM_STR)
951  ),
952  $queryBuilder->expr()->eq(
953  'fieldname',
954  $queryBuilder->createNamedParameter('categories', \PDO::PARAM_STR)
955  )
956  )
957  )
958  ->execute()
959  ->fetchColumn(0);
960  $this->assertEquals(4, $countCategories);
961  }
962 
968  public function adjustingMmRelationWithTablesnameAndFieldnameFieldDoNotTouchOtherRelations()
969  {
971  $postRepository = $this->objectManager->get(PostRepository::class);
973  $post = $postRepository->findByUid(1);
974  // Move category down
975  foreach ($post->getCategories() as $category) {
976  $post->removeCategory($category);
977  $post->addCategory($category);
978  break;
979  }
980  $postRepository->update($post);
981  $this->persistentManager->persistAll();
982 
983  // re-fetch Post and Blog
984  $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('sys_category_record_mm');
985  $queryBuilder->getRestrictions()
986  ->removeAll();
987  $newBlogCategoryCount = $queryBuilder
988  ->count('*')
989  ->from('sys_category_record_mm')
990  ->where(
991  $queryBuilder->expr()->andX(
992  $queryBuilder->expr()->eq(
993  'uid_foreign',
994  $queryBuilder->createNamedParameter($this->blog->getUid(), \PDO::PARAM_INT)
995  ),
996  $queryBuilder->expr()->eq(
997  'tablenames',
998  $queryBuilder->createNamedParameter('tx_blogexample_domain_model_post', \PDO::PARAM_STR)
999  ),
1000  $queryBuilder->expr()->eq(
1001  'fieldname',
1002  $queryBuilder->createNamedParameter('categories', \PDO::PARAM_STR)
1003  )
1004  )
1005  )
1006  ->execute()
1007  ->fetchColumn(0);
1008 
1009  $this->assertEquals($this->blog->getCategories()->count(), $newBlogCategoryCount);
1010  }
1011 
1015  public function distinctDataProvider()
1016  {
1017  return [
1018  'order default' => [
1019  []
1020  ],
1021  'order default, offset 0' => [
1022  [
1023  'offset' => 0
1024  ]
1025  ],
1026  'order default, limit 100' => [
1027  [
1028  'limit' => 100
1029  ]
1030  ],
1031  'order default, offset 0, limit 100' => [
1032  [
1033  'offset' => 0,
1034  'limit' => 100
1035  ]
1036  ],
1037  'order false' => [
1038  [
1039  'order' => false
1040  ]
1041  ],
1042  'order false, offset 0' => [
1043  [
1044  'order' => false,
1045  'offset' => 0
1046  ]
1047  ],
1048  'order false, limit 100' => [
1049  [
1050  'order' => false, 'limit' => 100
1051  ]
1052  ],
1053  'order false, offset 0, limit 100' => [
1054  [
1055  'order' => false,
1056  'offset' => 0,
1057  'limit' => 100
1058  ]
1059  ],
1060  'order uid, offset 0' => [
1061  [
1062  'order' => ['uid' => QueryInterface::ORDER_ASCENDING],
1063  'offset' => 0
1064  ]
1065  ],
1066  'order uid, limit 100' => [
1067  [
1068  'order' => ['uid' => QueryInterface::ORDER_ASCENDING],
1069  'limit' => 100
1070  ]
1071  ],
1072  'order uid, offset 0, limit 100' => [
1073  [
1074  'order' => ['uid' => QueryInterface::ORDER_ASCENDING],
1075  'offset' => 0,
1076  'limit' => 100
1077  ]
1078  ],
1079  ];
1080  }
1081 
1086  protected function applyQueryRequest(QueryInterface $query, array $queryRequest)
1087  {
1088  if (isset($queryRequest['order']) && !$queryRequest['order']) {
1089  $query->setOrderings([]);
1090  } elseif (!empty($queryRequest['order'])) {
1091  $query->setOrderings($queryRequest['order']);
1092  }
1093  if (isset($queryRequest['offset'])) {
1094  $query->setOffset($queryRequest['offset']);
1095  }
1096  if (isset($queryRequest['limit'])) {
1097  $query->setLimit($queryRequest['limit']);
1098  }
1099  }
1100 
1109  public function distinctPersonEntitiesAreFoundByPublisher(array $queryRequest)
1110  {
1111  $query = $this->provideFindPostsByPublisherQuery(1);
1112  $this->applyQueryRequest($query, $queryRequest);
1113  $posts = $query->execute();
1114  $postCount = $posts->count();
1115 
1116  $postIds = $this->resolveEntityIds($posts->toArray());
1117 
1118  $this->assertEquals($this->countDistinctIds($postIds), $postCount);
1119  $this->assertDistinctIds($postIds);
1120  }
1121 
1130  public function distinctPersonRecordsAreFoundByPublisher(array $queryRequest)
1131  {
1132  $query = $this->provideFindPostsByPublisherQuery(1);
1133  $this->applyQueryRequest($query, $queryRequest);
1134  $postRecords = $query->execute(true);
1135  $postIds = $this->resolveRecordIds($postRecords);
1136 
1137  $this->assertDistinctIds($postIds);
1138  }
1139 
1144  protected function provideFindPostsByPublisherQuery(int $publisherId)
1145  {
1146  $postRepository = $this->objectManager->get(PostRepository::class);
1147  $query = $postRepository->createQuery();
1148  $query->matching(
1149  $query->logicalOr([
1150  $query->equals('author.uid', $publisherId),
1151  $query->equals('reviewer.uid', $publisherId)
1152  ])
1153  );
1154  return $query;
1155  }
1156 
1165  public function distinctBlogEntitiesAreFoundByPostsSince(array $queryRequest)
1166  {
1167  $query = $this->provideFindBlogsByPostsSinceQuery(
1168  new \DateTime('2017-08-01')
1169  );
1170  $this->applyQueryRequest($query, $queryRequest);
1171  $blogs = $query->execute();
1172  $blogCount = $blogs->count();
1173 
1174  $blogIds = $this->resolveEntityIds($blogs->toArray());
1175 
1176  $this->assertEquals($this->countDistinctIds($blogIds), $blogCount);
1177  $this->assertDistinctIds($blogIds);
1178  }
1179 
1188  public function distinctBlogRecordsAreFoundByPostsSince(array $queryRequest)
1189  {
1190  $query = $this->provideFindBlogsByPostsSinceQuery(
1191  new \DateTime('2017-08-01')
1192  );
1193  $this->applyQueryRequest($query, $queryRequest);
1194  $blogRecords = $query->execute(true);
1195  $blogIds = $this->resolveRecordIds($blogRecords);
1196 
1197  $this->assertDistinctIds($blogIds);
1198  }
1199 
1204  protected function provideFindBlogsByPostsSinceQuery(\DateTime $date)
1205  {
1206  $blogRepository = $this->objectManager->get(BlogRepository::class);
1207  $query = $blogRepository->createQuery();
1208  $query->matching(
1209  $query->greaterThanOrEqual('posts.date', $date)
1210  );
1211  return $query;
1212  }
1213 
1222  public function distinctPersonEntitiesAreFoundByTagNameAreFiltered(array $queryRequest)
1223  {
1224  $query = $this->provideFindPersonsByTagNameQuery('SharedTag');
1225  $this->applyQueryRequest($query, $queryRequest);
1226  $persons = $query->execute();
1227  $personCount = $persons->count();
1228 
1229  $personIds = $this->resolveEntityIds($persons->toArray());
1230 
1231  $this->assertEquals($this->countDistinctIds($personIds), $personCount);
1232  $this->assertDistinctIds($personIds);
1233  }
1234 
1243  public function distinctPersonRecordsAreFoundByTagNameAreFiltered(array $queryRequest)
1244  {
1245  $query = $this->provideFindPersonsByTagNameQuery('SharedTag');
1246  $this->applyQueryRequest($query, $queryRequest);
1247  $personRecords = $query->execute(true);
1248  $personIds = $this->resolveRecordIds($personRecords);
1249 
1250  $this->assertDistinctIds($personIds);
1251  }
1252 
1257  protected function provideFindPersonsByTagNameQuery(string $tagName)
1258  {
1259  $personRepository = $this->objectManager->get(PersonRepository::class);
1260  $query = $personRepository->createQuery();
1261  $query->matching(
1262  $query->logicalOr([
1263  $query->equals('tags.name', $tagName),
1264  $query->equals('tagsSpecial.name', $tagName)
1265  ])
1266  );
1267  return $query;
1268  }
1269 
1278  public function distinctPostEntitiesAreFoundByAuthorTagNameAreFiltered(array $queryRequest)
1279  {
1280  $query = $this->provideFindPostsByAuthorTagName('SharedTag');
1281  $this->applyQueryRequest($query, $queryRequest);
1282  $posts = $query->execute();
1283  $postCount = $posts->count();
1284 
1285  $postsIds = $this->resolveEntityIds($posts->toArray());
1286 
1287  $this->assertEquals($this->countDistinctIds($postsIds), $postCount);
1288  $this->assertDistinctIds($postsIds);
1289  }
1290 
1299  public function distinctPostRecordsAreFoundByAuthorTagNameAreFiltered(array $queryRequest)
1300  {
1301  $query = $this->provideFindPostsByAuthorTagName('SharedTag');
1302  $this->applyQueryRequest($query, $queryRequest);
1303  $postRecords = $query->execute(true);
1304  $postsIds = $this->resolveRecordIds($postRecords);
1305 
1306  $this->assertDistinctIds($postsIds);
1307  }
1308 
1313  protected function provideFindPostsByAuthorTagName(string $tagName)
1314  {
1315  $postRepository = $this->objectManager->get(PostRepository::class);
1316  $query = $postRepository->createQuery();
1317  $query->matching(
1318  $query->logicalOr([
1319  $query->equals('author.tags.name', $tagName),
1320  $query->equals('author.tagsSpecial.name', $tagName)
1321  ])
1322  );
1323  return $query;
1324  }
1325 
1329  protected function updateAndPersistBlog()
1330  {
1332  $blogRepository = $this->objectManager->get(BlogRepository::class);
1333  $blogRepository->update($this->blog);
1334  $this->persistentManager->persistAll();
1335  }
1336 
1341  protected function resolveEntityIds(array $entities)
1342  {
1343  return array_map(
1344  function (AbstractEntity $entity) {
1345  return $entity->getUid();
1346  },
1347  $entities
1348  );
1349  }
1350 
1355  protected function resolveRecordIds(array $records)
1356  {
1357  return array_column($records, 'uid');
1358  }
1359 
1366  protected function countDistinctIds(array $ids)
1367  {
1368  return count(array_count_values($ids));
1369  }
1370 
1377  protected function assertDistinctIds(array $ids)
1378  {
1379  $counts = array_count_values($ids);
1380  $this->assertEquals(count($counts), array_sum($counts));
1381  }
1382 }
static makeInstance($className,... $constructorArguments)
applyQueryRequest(QueryInterface $query, array $queryRequest)