3 namespace RedUNIT\Base;
5 use RedUNIT\Base as Base;
6 use RedBeanPHP\Facade as R;
7 use RedBeanPHP\DuplicationManager as DuplicationManager;
8 use RedBeanPHP\OODBBean as OODBBean;
9 use RedBeanPHP\RedException as RedException;
14 * Tests duplication. Like the 'copy' test suite but
15 * focuses on more complex scenarios.
17 * @file RedUNIT/Base/Dup.php
18 * @desc Intensive test for dup()
19 * @author Gabor de Mooij and the RedBeanPHP Community
20 * @license New BSD/GPLv2
22 * (c) G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community.
23 * This source file is subject to the New BSD/GPLv2 License that is bundled
24 * with this source code in the file license.txt.
26 class Dup extends Base
29 * Tests whether the original ID is stored
30 * in meta data (quite handy for ID mappings).
32 public function testKeepOldID()
35 $book = R::dispense( 'book' );
36 $book->xownPageList[] = R::dispense( 'page' );
39 $page = reset( $book->xownPageList );
41 $book = $book->fresh();
42 $copy = R::duplicate( $book );
43 asrt( $copy->getMeta( 'sys.dup-from-id' ), $bookID );
44 $copyPage = reset( $copy->xownPageList );
45 asrt( $copyPage->getMeta( 'sys.dup-from-id' ), $pageID );
49 * Test export camelCase.
53 public function testExportCamelCase()
56 $book = R::dispense( 'book' );
57 $book->isCheap = true;
58 $book->hasISBNCode = false;
59 $page = R::dispense('page');
60 $page->isWrittenWell = true;
61 $page->containsInterestingText = true;
62 $book->ownPageList[] = $page;
64 $book = $book->fresh();
65 $export = R::exportAll( $book );
67 asrt( isset( $export[0]['id'] ), true );
68 asrt( isset( $export[0]['is_cheap'] ), true );
69 asrt( isset( $export[0]['has_isbn_code'] ), true );
70 asrt( isset( $export[0]['ownPage']['0']['id'] ), true );
71 asrt( isset( $export[0]['ownPage']['0']['is_written_well'] ), true );
72 asrt( isset( $export[0]['ownPage']['0']['contains_interesting_text'] ), true );
73 asrt( isset( $export[0]['ownPage']['0']['book_id'] ), true );
75 R::useExportCase( 'camel' );
76 $export = R::exportAll( $book );
77 asrt( isset( $export[0]['id'] ), true );
78 asrt( isset( $export[0]['isCheap'] ), true );
79 asrt( isset( $export[0]['hasIsbnCode'] ), true );
80 asrt( isset( $export[0]['ownPage']['0']['id'] ), true );
81 asrt( isset( $export[0]['ownPage']['0']['isWrittenWell'] ), true );
82 asrt( isset( $export[0]['ownPage']['0']['containsInterestingText'] ), true );
83 asrt( isset( $export[0]['ownPage']['0']['bookId'] ), true );
85 R::useExportCase( 'dolphin' );
86 $export = R::exportAll( $book );
87 asrt( isset( $export[0]['id'] ), true );
88 asrt( isset( $export[0]['isCheap'] ), true );
89 asrt( isset( $export[0]['hasIsbnCode'] ), true );
90 asrt( isset( $export[0]['ownPage']['0']['id'] ), true );
91 asrt( isset( $export[0]['ownPage']['0']['isWrittenWell'] ), true );
92 asrt( isset( $export[0]['ownPage']['0']['containsInterestingText'] ), true );
93 asrt( isset( $export[0]['ownPage']['0']['bookID'] ), true );
95 R::useExportCase( 'default' );
96 $export = R::exportAll( $book );
97 asrt( isset( $export[0]['id'] ), true );
98 asrt( isset( $export[0]['is_cheap'] ), true );
99 asrt( isset( $export[0]['has_isbn_code'] ), true );
100 asrt( isset( $export[0]['ownPage']['0']['id'] ), true );
101 asrt( isset( $export[0]['ownPage']['0']['is_written_well'] ), true );
102 asrt( isset( $export[0]['ownPage']['0']['contains_interesting_text'] ), true );
103 asrt( isset( $export[0]['ownPage']['0']['book_id'] ), true );
106 R::useExportCase( 'invalid' );
108 } catch ( RedException $exception ) {
114 * Test whether we can duplicate part of a tree
115 * without infinite loops.
119 public function testDupPortionOfATree()
122 $article = R::dispense( 'article' );
123 $article->name = 'article 1';
124 list( $article2, $article3 ) = R::dispense( 'article', 2 );
125 $article2->name = 'article 2';
126 $article3->name = 'article 3';
127 list( $article4, $article5 ) = R::dispense( 'article' , 2);
128 $article4->name = 'article 4';
129 $article5->name = 'article 5';
130 list( $article6, $article7 ) = R::dispense( 'article' , 2);
131 $article6->name = 'article 6';
132 $article7->name = 'article 7';
133 $article3->xownArticleList[] = $article7;
134 $article4->xownArticleList[] = $article6;
135 $article2->xownArticleList = array( $article5, $article4 );
136 $article->xownArticleList = array( $article2, $article3 );
137 R::store( $article );
138 asrt( R::count( 'article' ), 7 );
139 $article2 = $article2->fresh();
140 $dupArticle2 = R::duplicate( $article2 );
141 $dupArticle2->name = 'article 2b';
142 $dupBeans = $dupArticle2->xownArticleList;
143 foreach( $dupBeans as $dupBean ) {
144 $list[] = $dupBean->name;
147 $listStr = implode( ',', $list );
148 asrt( $listStr, 'article 4,article 5' );
149 foreach( $dupBeans as $dupBean ) {
150 if ( $dupBean->name === 'article 4' ) {
154 asrt( isset( $dup4 ), TRUE );
155 $dupBeans = $dup4->xownArticleList;
156 foreach( $dupBeans as $dupBean ) {
157 asrt( $dupBean->name, 'article 6' );
160 //so we have extracted part of the tree, can we store it?
161 $id = R::store( $dupArticle2 );
162 asrt( ( $id > 0 ), TRUE );
163 asrt( R::count( 'article' ), 11 );
165 $originalArticle = $article->fresh();
166 asrt( $originalArticle->name, 'article 1' );
168 $subArticles = $originalArticle->xownArticleList;
170 foreach( $subArticles as $subArticle ) {
171 $list[] = $subArticle->name;
174 $listStr = implode( ',', $list );
175 asrt( $listStr, 'article 2,article 2b,article 3' );
177 foreach( $subArticles as $subArticle ) {
178 if ( $subArticle->name === 'article 2' ) {
181 if ( $subArticle->name === 'article 3' ) {
186 $subArticles = $sub2->xownArticleList;
188 foreach( $subArticles as $subArticle ) {
189 $list[] = $subArticle->name;
192 $listStr = implode( ',', $list );
193 asrt( $listStr, 'article 4,article 5' );
195 $subArticles = $sub3->xownArticleList;
197 foreach( $subArticles as $subArticle ) {
198 $list[] = $subArticle->name;
201 $listStr = implode( ',', $list );
202 asrt( $listStr, 'article 7' );
204 $subArticles = $sub2->xownArticleList;
205 foreach( $subArticles as $subArticle ) {
206 if ( $subArticle->name === 'article 4' ) {
209 if ( $subArticle->name === 'article 5' ) {
214 asrt( count( $sub4->xownArticleList ), 1 );
215 $subBeans = $sub4->xownArticleList;
216 $subBean = reset( $subBeans );
217 asrt( $subBean->name, 'article 6');
219 asrt( count( $sub5->xownArticleList ), 0 );
221 $dupArticle2 = $dupArticle2->fresh();
222 $subArticles = $dupArticle2->xownArticleList;
224 foreach( $subArticles as $subArticle ) {
225 $list[] = $subArticle->name;
228 $listStr = implode( ',', $list );
229 asrt( $listStr, 'article 4,article 5' );
231 foreach( $subArticles as $subArticle ) {
232 if ( $subArticle->name === 'article 4' ) {
235 if ( $subArticle->name === 'article 5' ) {
240 asrt( count( $sub4->xownArticleList ), 1 );
241 $subBeans = $sub4->xownArticleList;
242 $subBean = reset( $subBeans );
243 asrt( $subBean->name, 'article 6');
245 asrt( count( $sub5->xownArticleList ), 0 );
249 * Test exportAll and caching.
253 public function testExportAllAndCache()
255 testpack( 'exportAll() and Cache' );
257 $can = R::dispense( 'can' )->setAttr( 'size', 3 );
259 $can->ownCoffee[] = R::dispense( 'coffee' )->setAttr( 'color', 'black' );
260 $can->sharedTag[] = R::dispense( 'tag' )->setAttr( 'name', 'cool' );
262 $id = R::store( $can );
268 $can = R::load( 'can', $id );
270 $cache = $this->getCache();
272 $data = R::exportAll( array( $can ), TRUE );
274 $queries = ob_get_contents();
278 $len1 = strlen( $queries );
280 $can = R::dispense( 'can' )->setAttr( 'size', 3 );
281 $can->ownCoffee[] = R::dispense( 'coffee' )->setAttr( 'color', 'black' );
282 $can->sharedTag[] = R::dispense( 'tag' )->setAttr( 'name', 'cool' );
284 $id = R::store( $can );
290 $can = R::load( 'can', $id );
292 $cache = $this->getCache();
294 $data = R::exportAll( array( $can ), TRUE );
296 $queries = ob_get_contents();
302 $len2 = strlen( $queries );
304 asrt( ( $len1 ), ( $len2 ) );
306 $can = R::dispense( 'can' )->setAttr( 'size', 3 );
308 $can->ownCoffee[] = R::dispense( 'coffee' )->setAttr( 'color', 'black' );
309 $can->sharedTag[] = R::dispense( 'tag' )->setAttr( 'name', 'cool' );
311 $id = R::store( $can );
317 $can = R::load( 'can', $id );
319 $cache = $this->getCache();
321 R::getDuplicationManager()->setTables( $cache );
323 $data = R::exportAll( array( $can ), TRUE );
325 $queries = ob_get_contents();
331 $len3 = strlen( $queries );
333 asrt( ( ( $len3 ) < ( $len2 ) ), TRUE );
334 asrt( count( $data ), 1 );
335 asrt( $data[0]['ownCoffee'][0]['color'], 'black' );
337 R::getDuplicationManager()->setCacheTables( FALSE );
341 * Test duplication and caching.
345 public function DupAndCache()
347 testpack( 'Dup() and Cache' );
349 $can = R::dispense( 'can' )->setAttr( 'size', 3 );
351 $can->ownCoffee[] = R::dispense( 'coffee' )->setAttr( 'color', 'black' );
352 $can->sharedTag[] = R::dispense( 'tag' )->setAttr( 'name', 'cool' );
354 $can = R::load( 'can', R::store( $can ) );
356 $d = new DuplicationManager( R::getToolBox() );
358 $d->setCacheTables( TRUE );
364 $x = $d->dup( $can );
366 $queries = ob_get_contents();
372 $len1 = strlen( $queries );
374 asrt( ( $len1 > 40 ), TRUE );
375 asrt( isset( $x->ownCoffee ), TRUE );
376 asrt( count( $x->ownCoffee ), 1 );
377 asrt( isset( $x->sharedTag ), TRUE );
378 asrt( count( $x->sharedTag ), 1 );
380 $cache = $d->getSchema();
384 $can = R::dispense( 'can' )->setAttr( 'size', 3 );
386 $can->ownCoffee[] = R::dispense( 'coffee' )->setAttr( 'color', 'black' );
387 $can->sharedTag[] = R::dispense( 'tag' )->setAttr( 'name', 'cool' );
389 $can = R::load( 'can', R::store( $can ) );
391 $d = new DuplicationManager( R::getToolBox() );
394 * $cache = '{"book": {
403 * "nome_meio": "TEXT",
404 * "sobrenome": "TEXT",
405 * "nascimento": "NUMERIC",
406 * "reg_owner": "TEXT"
409 * "nome_documento": "TEXT",
410 * "numero_documento": "TEXT",
411 * "reg_owner": "TEXT",
412 * "ownPessoa_id": "INTEGER"
419 * "can_id": "INTEGER"
425 * "tag_id": "INTEGER",
426 * "can_id": "INTEGER"
430 $d->setTables( $cache );
436 $x = $d->dup( $can );
438 $queries = ob_get_contents();
444 $len2 = strlen( $queries );
446 asrt( isset( $x->ownCoffee ), TRUE );
447 asrt( count( $x->ownCoffee ), 1 );
448 asrt( isset( $x->sharedTag ), TRUE );
449 asrt( count( $x->sharedTag ), 1 );
450 asrt( json_encode( $cache ), json_encode( $d->getSchema() ) );
451 asrt( ( $len1 > $len2 ), TRUE );
455 * Test duplication and tainting.
459 public function testDupAndExportNonTainting()
461 testpack( 'Dup() and Export() should not taint beans' );
463 $p = R::dispense( 'page' );
464 $b = R::dispense( 'book' );
469 $id = R::store( $b );
471 $b = R::load( 'book', $id );
473 asrt( ( !$b->getMeta( 'tainted' ) ), TRUE );
477 asrt( ( !$b->getMeta( 'tainted' ) ), TRUE );
481 asrt( ( !$b->getMeta( 'tainted' ) ), TRUE );
483 testpack( 'Test issue with ownItems and stealing Ids.' );
486 $bill = R::dispense( 'bill' );
487 $item = R::dispense( 'item' );
488 $element = R::dispense( 'element' );
489 $bill->ownItem[] = $item;
490 $bill->sharedElement[] = $element;
492 $bill = R::load( 'bill', 1 );
494 $bill->sharedElement;
495 $copy = R::dup( $bill );
498 $rows = ( R::getAll( 'select * from bill_element' ) );
499 asrt( count( $rows ), 2 );
501 $rows = ( R::getAll( 'select * from item' ) );
503 foreach ( $rows as $row ) {
504 asrt( ( $row['bill_id'] > 0 ), TRUE );
513 $this->runOnce( FALSE );
519 * Test exporting with filters.
523 public function ExportWithFilters()
525 testpack( 'Export with filters' );
527 $book = R::dispense( 'book' );
528 $pages = R::dispense( 'page', 2 );
529 $texts = R::dispense( 'text', 2 );
530 $images = R::dispense( 'image', 2 );
531 $author = R::dispense( 'author' );
532 $pub = R::dispense( 'publisher' );
533 $bookmarks = R::dispense( 'bookmark', 2 );
535 $pages[0]->ownText = array( $texts[0] );
536 $pages[0]->ownImage = array( $images[0] );
537 $pages[1]->ownText = array( $texts[1] );
538 $pages[1]->ownImage = array( $images[1] );
540 $pages[0]->sharedBookmark[] = $bookmarks[0];
541 $pages[1]->sharedBookmark[] = $bookmarks[1];
543 $bookmarks[0]->ownNote[] = R::dispense( 'note' )->setAttr( 'text', 'a note' );
544 $bookmarks[1]->ownNote[] = R::dispense( 'note' )->setAttr( 'text', 'a note' );
546 $book->ownPage = $pages;
547 $book->author = $author;
549 $author->publisher = $pub;
550 $bookID = R::store( $book );
552 R::getDuplicationManager()->setTables( R::getWriter()->getTables() );
554 $objects = ( R::exportAll( array( $book ), TRUE, array() ) );
556 asrt( isset( $objects[0]['ownPage'] ), TRUE );
557 asrt( count( $objects[0]['ownPage'] ), 2 );
558 asrt( isset( $objects[0]['author'] ), TRUE );
559 asrt( isset( $objects[0]['ownPage'][0]['ownText'] ), TRUE );
560 asrt( count( $objects[0]['ownPage'][0]['ownText'] ), 1 );
561 asrt( isset( $objects[0]['ownPage'][0]['ownImage'] ), TRUE );
562 asrt( count( $objects[0]['ownPage'][0]['ownImage'] ), 1 );
564 $objects = ( R::exportAll( array( $book ), TRUE, array( 'page', 'author', 'text', 'image' ) ) );
566 asrt( isset( $objects[0]['ownPage'] ), TRUE );
567 asrt( count( $objects[0]['ownPage'] ), 2 );
568 asrt( isset( $objects[0]['author'] ), TRUE );
569 asrt( isset( $objects[0]['ownPage'][0]['ownText'] ), TRUE );
570 asrt( count( $objects[0]['ownPage'][0]['ownText'] ), 1 );
571 asrt( isset( $objects[0]['ownPage'][0]['ownImage'] ), TRUE );
572 asrt( count( $objects[0]['ownPage'][0]['ownImage'] ), 1 );
574 $objects = ( R::exportAll( array( $book ), TRUE, 'author' ) );
576 asrt( isset( $objects[0]['ownPage'] ), FALSE );
577 asrt( isset( $objects[0]['ownPage'][0]['ownText'] ), FALSE );
579 $objects = ( R::exportAll( array( $book ), TRUE, array( 'page' ) ) );
581 asrt( isset( $objects[0]['author'] ), FALSE );
582 asrt( isset( $objects[0]['ownPage'][0]['ownText'] ), FALSE );
584 $objects = ( R::exportAll( array( $book ), TRUE, array( 'page', 'text' ) ) );
586 asrt( isset( $objects[0]['author'] ), FALSE );
587 asrt( isset( $objects[0]['ownPage'] ), TRUE );
588 asrt( isset( $objects[0]['ownPage'][0]['ownText'] ), TRUE );
589 asrt( count( $objects[0]['ownPage'][0]['ownText'] ), 1 );
590 asrt( isset( $objects[0]['ownPage'][0]['ownImage'] ), FALSE );
592 $objects = ( R::exportAll( array( $book ), TRUE, array( 'none' ) ) );
594 asrt( isset( $objects[0]['author'] ), FALSE );
595 asrt( isset( $objects[0]['ownPage'] ), FALSE );
597 $texts = R::find( 'text' );
599 R::getDuplicationManager()->setCacheTables( FALSE );
601 testpack( 'Keyless export' );
603 $book = R::load( 'book', $bookID );
607 $export = $book->export();
609 asrt( isset( $export['ownPage'][0] ), TRUE );
614 * Helper function getCache().
618 private function getCache()
632 'can_id' => 'can_id',
642 * Compares object with export
644 * @param type $object
647 private function compare( $object, $array )
649 foreach ( $object as $property => $value ) {
650 if ( is_array( $value ) ) {
651 foreach ( $value as $index => $nestedObject ) {
652 if ( $nestedObject->id ) {
654 //order might be different
655 foreach ( $array[$property] as $k => $a ) {
656 if ( $a['id'] == $nestedObject->id ) {
661 if ( !$foundMatch ) throw new\Exception( 'failed to find match for object ' . $nestedObject->id );
663 $this->compare( $nestedObject, $array[$property][$index] );
665 } elseif ( !is_object( $value ) ) {
666 asrt( strval( $array[$property] ), strval( $value ) );
674 private function runOnce( $n = TRUE )
677 $books = R::dispense( 'book', 10 );
678 $pages = R::dispense( 'page', 10 );
679 $readers = R::dispense( 'reader', 10 );
680 $texts = R::dispense( 'text', 10 );
683 foreach ( $books as $book ) $book->name = 'book-' . ( $i++ );
685 foreach ( $pages as $page ) $page->name = 'page-' . ( $i++ );
687 foreach ( $readers as $reader ) $reader->name = 'reader-' . ( $i++ );
689 foreach ( $texts as $text ) $text->content = 'lorem ipsum -' . ( $i++ );
691 foreach ( $texts as $text ) {
692 $pages[array_rand( $pages )]->ownText[] = $text;
694 foreach ( $pages as $page ) {
695 $books[array_rand( $books )]->ownPage[] = $page;
697 foreach ( $readers as $reader ) {
698 $books[array_rand( $books )]->sharedReader[] = $reader;
700 $i = $noOfReaders = $noOfPages = $noOfTexts = 0;
701 foreach ( $books as $key => $book ) {
703 $noOfPages += count( $book->ownPage );
704 $noOfReaders += count( $book->sharedReader );
705 foreach ( $book->ownPage as $page ) $noOfTexts += count( $page->ownText );
706 $arr = R::exportAll( $book );
707 echo "\nIntermediate info: " . json_encode( $arr ) . ": Totals = $i,$noOfPages,$noOfReaders,$noOfTexts ";
709 $this->compare( $book, $arr[0] );
710 $copiedBook = R::dup( $book );
711 $copiedBookArray = R::exportAll( $copiedBook );
712 $this->compare( $book, $copiedBookArray[0] );
713 $copiedBookArrayII = $copiedBook->export();
714 $this->compare( $book, $copiedBookArrayII );
715 $copyFromCopy = R::dup( $copiedBook );
716 $copyFromCopyArray = R::exportAll( $copyFromCopy );
717 $this->compare( $book, $copyFromCopyArray[0] );
718 $copyFromCopyArrayII = $copyFromCopy->export();
719 $this->compare( $book, $copyFromCopyArrayII );
720 $id = R::store( $book );
721 $copiedBook = R::dup( $book );
722 R::store( $book ); //should not be damaged
723 $copiedBookArray = R::exportAll( $copiedBook );
724 $originalBookArray = R::exportAll( $book );
725 $this->compare( $copiedBook, $copiedBookArray[0] );
726 $this->compare( $book, $originalBookArray[0] );
727 $book = R::load( 'book', $id );
728 $this->compare( $book, $originalBookArray[0] );
729 $copiedBook = R::dup( $book );
730 $this->compare( $copiedBook, $copiedBook->export() );
731 R::store( $copiedBook );
732 $this->compare( $copiedBook, $copiedBook->export() );
733 $copyFromCopy = R::dup( $copiedBook );
734 $this->compare( $copyFromCopy, $copyFromCopy->export() );
735 R::store( $copyFromCopy );
736 $newPage = R::dispense( 'page' );
737 $newPage->name = 'new';
738 $copyFromCopy->ownPage[] = $newPage;
739 $modifiedCopy = R::dup( $copyFromCopy );
740 $exportMod = R::exportAll( $modifiedCopy );
741 $this->compare( $modifiedCopy, $exportMod[0] );
742 asrt( count( $modifiedCopy->ownPage ), count( $copiedBook->ownPage ) + 1 );
743 R::store( $modifiedCopy );
746 asrt( (int) R::getCell( 'SELECT count(*) FROM book' ), $i * 4 );
747 asrt( (int) R::getCell( 'SELECT count(*) FROM page' ), ( $noOfPages * 4 ) + $i );
748 asrt( (int) R::getCell( 'SELECT count(*) FROM text' ), $noOfTexts * 4 );
749 asrt( (int) R::getCell( 'SELECT count(*) FROM book_reader' ), $noOfReaders * 4 );
750 asrt( (int) R::getCell( 'SELECT count(*) FROM reader' ), $noOfReaders );
755 asrt( $noOfTexts, 10 );
756 asrt( $noOfReaders, 10 );
757 asrt( $noOfPages, 10 );