3 namespace RedUNIT\Base;
5 use RedUNIT\Base as Base;
6 use RedBeanPHP\Facade as R;
7 use RedBeanPHP\RedException as RedException;
8 use RedBeanPHP\OODBBean as OODBBean;
13 * Tests whether RedBeanPHP handles relational data properly.
14 * This test suite is quite large because it tests various types
15 * of relations as well as simple and complex usage scenarios.
17 * @file RedUNIT/Base/Relations.php
18 * @desc Tests N:1 relations, nested beans.
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 Relations extends Base
29 * Test whether untainted parent bean dont
34 public function testDontSaveParentIfNotTainted()
37 $author = R::dispense( 'author' );
39 $book = R::dispense( 'book' );
40 $book->author = $author;
41 $book->author->name = 'x';
42 $book->author->setMeta( 'tainted', false );
44 $author = $author->fresh();
45 asrt( isset( $author->name ), false );
49 * Tests whether via() applies camelcase-to-snakecase
50 * conversion. Although most of the time you do not need
51 * this since via() is meant to remap typical link tables
56 public function testCamelCasingVia()
59 $book = R::dispense('book');
60 $book->sharedPage[] = R::dispense('page');
62 $book = $book->fresh();
63 asrt( count( $book->via('bookPage')->sharedPage ), 1 );
64 $book = $book->fresh();
65 asrt( count( $book->via('book_page')->sharedPage ), 1 );
69 * Test whether we can't add more than one FK.
71 public function testDuplicateFK()
74 list( $book, $page ) = R::dispenseAll( 'book,page' );
75 $book->sharedPage[] = $page;
78 $writer = R::getWriter();
79 $added1 = $writer->addFK( 'book_page', 'book', 'book_id', 'id', TRUE );
80 $added2 = $writer->addFK( 'book_page', 'page', 'page_id', 'id', TRUE );
81 $added = ( $added1 && $added2 );
82 asrt( $added, FALSE );
86 * Test whether ->all() reloads a list.
90 public function testAllPrefix()
93 $book = R::dispense( 'book' );
94 $book->ownPage = R::dispense( 'page', 10 );
95 $book->sharedTag = R::dispense( 'tag', 2 );
97 foreach( $book->ownPage as $page ) {
101 $book = $book->fresh();
102 asrt( count( $book->ownPage ), 10 );
103 asrt( count( $book->withCondition(' pageno < 5 ')->ownPage ), 5 );
104 asrt( count( $book->ownPage ), 5 );
105 asrt( count( $book->all()->ownPage ), 10 );
106 asrt( count( $book->with(' LIMIT 3 ')->ownPage ), 3 );
107 asrt( count( $book->ownPage ), 3 );
108 asrt( count( $book->all()->ownPage ), 10 );
109 asrt( count( $book->sharedTag ), 2 );
110 asrt( count( $book->with( ' LIMIT 1 ' )->sharedTag ), 1 );
111 asrt( count( $book->sharedTag ), 1 );
112 asrt( count( $book->all()->sharedTag ), 2 );
116 * Test Relations and conditions.
120 public function testRelationsAndConditions()
122 list( $book1, $book2 ) = R::dispense( 'book', 2 );
123 list( $page1, $page2, $page3, $page4 ) = R::dispense( 'page', 4 );
124 list( $author1, $author2 ) = R::dispense( 'author', 2 );
127 $page1->thename = '1';
128 $page2->thename = '2';
129 $page3->thename = '3';
130 $page3->thename = '4';
131 $book1->ownPage = array( $page1, $page2 );
132 $book2->ownPage = array( $page3, $page4 );
133 $author1->sharedBook = array( $book1, $book2 );
134 $author2->sharedBook = array( $book2 );
135 R::storeAll( array( $author1, $author2 ) );
136 asrt( count( $author1->sharedBook ), 2 );
137 asrt( count( $author1->withCondition( ' title = ? ', array( 'a' ) )->sharedBook ), 1 );
138 R::store( $author1 );
139 asrt( count( $author1->sharedBook ), 2 );
140 asrt( count( $author1->withCondition( ' xtitle = ? ', array( 'a' ) )->sharedBook ), 0 );
141 R::store( $author1 );
142 asrt( count( $author1->sharedBook ), 2 );
143 $book1 = R::load( 'book', $book1->id );
144 $book2 = $book2->fresh();
145 asrt( count( $book1->ownPage ), 2 );
146 asrt( count( $book1->with( ' LIMIT 1 ' )->ownPage ), 1 );
147 $book1 = $book1->fresh();
148 asrt( count( $book1->ownPage ), 2 );
149 asrt( count( $book1->withCondition( ' thename = ? ', array( '1' ) )->ownPage ), 1 );
153 * Test filtering relations on links (using columns in the link table).
157 public function testSharedLinkCond()
159 testpack( 'Test new shared relations with link conditions' );
161 list( $b1, $b2 ) = R::dispense( 'book', 2 );
164 list( $p1, $p2, $p3 ) = R::dispense( 'page', 3 );
169 $b1->link( 'book_page', array( 'order' => 1 ) )->page = $p1;
170 $b1->link( 'bookPage', array( 'order' => 2 ) )->page = $p2;
171 $b2->link( 'book_page', array( 'order' => 1 ) )->page = $p3;
172 $b2->link( 'bookPage', array( 'order' => 2 ) )->page = $p2;
173 $b2->link( 'book_page', array( 'order' => 3 ) )->page = $p1;
174 R::storeAll( array( $b1, $b2 ) );
175 $b1 = R::load( 'book', $b1->id );
176 $b2 = R::load( 'book', $b2->id );
177 $pages = $b1->withCondition( ' book_page.' . $w->esc( 'order' ) . ' = 2 ' )->sharedPage;
178 $page = reset( $pages );
179 asrt( $page->text, 'page2' );
180 $pages = $b2->withCondition( ' ' . $w->esc( 'order' ) . ' = 3 ' )->sharedPage;
181 $page = reset( $pages );
182 asrt( $page->text, 'page1' );
183 $b1 = R::load( 'book', $b1->id );
184 $b2 = R::load( 'book', $b2->id );
185 $pages = $b1->withCondition( ' book_page.' . $w->esc( 'order' ) . ' < 3 AND page.number = 3' )->sharedPage;
186 $page = reset( $pages );
187 asrt( $page->text, 'page1' );
188 $pages = $b2->withCondition( ' ' . $w->esc( 'order' ) . ' > 1 ORDER BY book_page.' . $w->esc( 'order' ) . ' ASC ' )->sharedPage;
189 $page = array_shift( $pages );
190 asrt( $page->text, 'page2' );
191 $page = array_shift( $pages );
192 asrt( $page->text, 'page1' );
193 testpack( 'Test new shared relations and cache' );
196 * why does this not destroy cache in psql?
197 * ah: An error occurred: SQLSTATE[42703]: Undefined column: 7
198 * ERROR: column "page" of relation "page" does not exist
200 R::exec( 'UPDATE page SET ' . $w->esc( 'number' ) . ' = 1 ' );
201 R::getWriter()->setUseCache( TRUE );
202 $p1 = R::load( 'page', (int) $p1->id );
203 // Someone else changes the records. Cache remains.
204 R::exec( ' UPDATE page SET ' . $w->esc( 'number' ) . ' = 9 -- keep-cache' );
205 $b1 = R::load( 'book', $b1->id );
206 $p1 = R::load( 'page', (int) $p1->id );
207 // Yupz a stale cache, phantom read!
208 asrt( (int) $p1->number, 1 );
209 $pages = $b1->withCondition( ' book_page.' . $w->esc( 'order' ) . ' = 1 ' )->sharedPage;
210 $page = reset( $pages );
211 // Inconsistent, sad but TRUE, different query -> cache key is different
212 asrt( (int) $page->number, 9 );
213 // However, cache must have been invalidated by this query
214 $p1 = R::load( 'page', (int) $p1->id );
215 // Yes! we're consistent again! -- as if the change just happened later!
216 asrt( (int) $page->number, 9 );
217 // By doing this we keep getting 9 instead of 8
218 $b1->fresh()->withCondition( ' book_page.' . $w->esc( 'order' ) . ' = 1 ' )->sharedPage;
219 // Someone else is busy again...
220 R::exec( ' UPDATE page SET ' . $w->esc( 'number' ) . ' = 8 -- keep-cache' );
221 $b1 = R::load( 'book', $b1->id );
222 $pages = $b1->withCondition( ' book_page.' . $w->esc( 'order' ) . ' = 1 ' )->sharedPage;
223 $page = reset( $pages );
226 * yes! we get 9 instead of 8, why because the cache key has not changed,
227 * our last query was PAGE-BOOK-RELATION and now we ask for
228 * PAGE-BOOK-RELATION again. if we would have used just a load page
229 * query we would have gotten the new value (8).... let's test that!
231 asrt( (int) $page->number, 9 );
232 R::exec( ' UPDATE page SET ' . $w->esc( 'number' ) . ' = 9' );
233 $p1 = R::load( 'page', (int) $p1->id );
234 asrt( (int) $page->number, 9 );
235 // Someone else is busy again...
236 R::exec( ' UPDATE page SET ' . $w->esc( 'number' ) . ' = 8 -- keep-cache' );
237 $b1 = R::load( 'book', $b1->id );
238 $pages = $b1->withCondition( ' book_page.' . $w->esc( 'order' ) . ' = 1 ' )->sharedPage;
239 $page = reset( $pages );
240 // Yes, keep-cache wont help, cache key changed!
241 asrt( (int) $page->number, 8 );
242 R::getWriter()->setUseCache( FALSE );
246 * Test related count using via().
250 public function testRelatedCountVia()
252 testpack( 'Test relatedCount with via()' );
253 $shop = R::dispense( 'shop' );
254 $shop->ownRelation = R::dispense( 'relation', 13 );
255 foreach ( $shop->ownRelation as $relation ) {
256 $relation->shop = $shop;
257 $relation->customer = R::dispense( 'customer' );
260 $shop = $shop->fresh();
261 asrt( $shop->via( 'relation' )->countShared( 'customer' ), 13 );
265 * Test counting and aliasing.
269 public function testCountingAndAliasing()
271 $book = R::dispense( 'book' );
272 $book->ownPage = R::dispense( 'page', 10 );
273 $book2 = R::dispense( 'book' );
274 $book2->ownPage = R::dispense( 'page', 4 );
275 list( $Bill, $James, $Andy ) = R::dispense( 'person', 3 );
276 $book->author = $Bill;
277 $book->coAuthor = $James;
278 $book2->author = $Bill;
279 $book2->coAuthor = $Andy;
282 $notes = R::dispense( 'note', 10 );
283 $book->sharedNote = array( $notes[0], $notes[1], $notes[2] );
284 $book2->sharedNote = array( $notes[3], $notes[4], $notes[1], $notes[0] );
285 $books = R::dispense( 'book', 5 );
286 $books[2]->title = 'boe';
287 $book->sharedBook = array( $books[0], $books[1] );
288 $book2->sharedBook = array( $books[0], $books[2], $books[4] );
289 R::storeAll( array( $book, $book2 ) );
290 asrt( $book->countOwn( 'page' ), 10 );
291 asrt( $book->withCondition( ' id < 5 ' )->countOwn( 'page' ), 4 );
292 asrt( $Bill->alias( 'author' )->countOwn( 'book' ), 2 );
293 asrt( $Andy->alias( 'coAuthor' )->countOwn( 'book' ), 1 );
294 asrt( $James->alias( 'coAuthor' )->countOwn( 'book' ), 1 );
295 asrt( $Bill->alias( 'author' )->countOwn( 'book' ), 2 );
296 asrt( $book->countShared( 'note' ), 3 );
297 asrt( $book2->countShared( 'note' ), 4 );
298 asrt( $book2->countShared( 'book' ), 3 );
299 $book2 = $book2->fresh();
300 asrt( $book2->withCondition( ' title = ? ', array( 'boe' ) )->countShared( 'book' ), 1 );
308 public function testVia()
310 testpack( 'Test via()' );
311 $d = R::dispense( 'doctor' )->setAttr( 'name', 'd1' );
312 $p = R::dispense( 'patient' )->setAttr( 'name', 'p1' );
313 $d->via( 'consult' )->sharedPatient[] = $p;
315 $d = R::load( 'doctor', $d->id );
316 asrt( count( $d->sharedPatient ), 1 );
317 asrt( in_array( 'consult', R::getWriter()->getTables() ), TRUE );
321 * Issue #348 via() should reload shared list
325 public function testIssue348()
327 $product = R::dispense( 'product' );
328 $product->name = 'test';
329 $color = R::dispense( 'color' );
330 $color->name = 'cname';
331 $color->code = 'ccode';
332 R::store( $product );
334 $product->link( 'productColor', array(
338 R::store( $product );
339 asrt( count( $product->sharedColor ), 0 );
340 asrt( count( $product->via( 'product_color' )->sharedColor ), 1 );
341 asrt( count( $product->sharedColor ), 1 );
342 R::renameAssociation( 'color_product', NULL );
346 * Test creation of link table.
350 public function testCreationOfLinkTable()
352 asrt( in_array( 'consult', R::getWriter()->getTables() ), FALSE );
353 $d = R::dispense( 'doctor' )->setAttr( 'name', 'd1' );
354 $p = R::dispense( 'patient' )->setAttr( 'name', 'p1' );
355 $d->sharedPatient[] = $p;
357 asrt( in_array( 'consult', R::getWriter()->getTables() ), TRUE );
361 * Fast track link block code should not affect self-referential N-M relations.
365 public function testFastTrackRelations()
367 testpack( 'Test fast-track linkBlock exceptions' );
368 list( $donald, $mickey, $goofy, $pluto ) = R::dispense( 'friend', 4 );
373 $donald->sharedFriend = array( $mickey, $goofy );
374 $mickey->sharedFriend = array( $pluto, $goofy );
375 $mickey->sharedBook = array( R::dispense( 'book' ) );
376 R::storeAll( array( $mickey, $donald, $goofy, $pluto ) );
377 $donald = R::load( 'friend', $donald->id );
378 $mickey = R::load( 'friend', $mickey->id );
379 $goofy = R::load( 'friend', $goofy->id );
380 $pluto = R::load( 'friend', $pluto->id );
381 $names = implode( ',', R::gatherLabels( $donald->sharedFriend ) );
382 asrt( $names, 'G,M' );
383 $names = implode( ',', R::gatherLabels( $goofy->sharedFriend ) );
384 asrt( $names, 'D,M' );
385 $names = implode( ',', R::gatherLabels( $mickey->sharedFriend ) );
386 asrt( $names, 'D,G,P' );
387 $names = implode( ',', R::gatherLabels( $pluto->sharedFriend ) );
389 // Now in combination with with() conditions...
390 $donald = R::load( 'friend', $donald->id );
391 $names = implode( ',', R::gatherLabels( $donald->withCondition( ' name = ? ', array( 'M' ) )->sharedFriend ) );
393 // Now in combination with with() conditions...
394 $donald = R::load( 'friend', $donald->id );
395 $names = implode( ',', R::gatherLabels( $donald->with( ' ORDER BY name ' )->sharedFriend ) );
396 asrt( $names, 'G,M' );
398 $goofy = R::load( 'friend', $goofy->id );
399 asrt( (int) $goofy->countShared( 'friend' ), 2 );
400 asrt( (int) $donald->countShared( 'friend' ), 2 );
401 asrt( (int) $mickey->countShared( 'friend' ), 3 );
402 asrt( (int) $pluto->countShared( 'friend' ), 1 );
406 * Test list beautifications.
410 public function testListBeautifications()
412 testpack( 'Test list beautifications' );
413 $book = R::dispense( 'book' );
414 $page = R::dispense( 'page' )->setAttr( 'name', 'a' );
415 $book->sharedPage[] = $page;
416 $id = R::store( $book );
417 $book = R::load( 'book', $id );
418 $p = reset( $book->ownBookPage );
419 asrt( $p->page->name, 'a' );
420 $bean = R::dispense( 'bean' );
421 $bean->sharedAclRole[] = R::dispense( 'role' )->setAttr( 'name', 'x' );
423 asrt( R::count( 'role' ), 1 );
424 $aclrole = R::getRedBean()->dispense( 'acl_role' );
425 $aclrole->name = 'role';
426 $bean = R::dispense( 'bean' );
427 $bean->sharedAclRole[] = $aclrole;
429 asrt( count( $bean->sharedAclRole ), 1 );
433 * Test list add and delete.
437 public function testListAddDelete()
439 testpack( 'Test list add/delete scenarios.' );
441 $b = R::dispense( 'book' );
442 $p = R::dispense( 'page' );
447 $b->xownPage = array();
449 asrt( R::count( 'page' ), 0 );
450 $p = R::dispense( 'page' );
451 $z = R::dispense( 'paper' );
454 asrt( R::count( 'page' ), 1 );
455 $z->xownPage = array();
457 asrt( R::count( 'page' ), 0 );
458 $i = R::dispense( 'magazine' );
459 $i->ownPage[] = R::dispense( 'page' );
461 asrt( R::count( 'page' ), 1 );
462 $i->ownPage = array();
464 asrt( R::count( 'page' ), 1 );
468 * Test basic and complex common usage scenarios for
469 * relations and associations.
473 public function testScenarios()
475 list( $q1, $q2 ) = R::dispense( 'quote', 2 );
476 list( $pic1, $pic2 ) = R::dispense( 'picture', 2 );
477 list( $book, $book2, $book3 ) = R::dispense( 'book', 4 );
478 list( $topic1, $topic2, $topic3, $topic4, $topic5 ) = R::dispense( 'topic', 5 );
479 list( $page1, $page2, $page3, $page4, $page5, $page6, $page7 ) = R::dispense( 'page', 7 );
482 $book->title = 'abc';
483 $book2->title = 'def';
484 $book3->title = 'ghi';
485 $page1->title = 'pagina1';
486 $page2->title = 'pagina2';
487 $page3->title = 'pagina3';
488 $page4->title = 'pagina4';
489 $page5->title = 'pagina5';
490 $page6->title = 'cover1';
491 $page7->title = 'cover2';
492 $topic1->name = 'holiday';
493 $topic2->name = 'cooking';
494 $topic3->name = 'gardening';
495 $topic4->name = 'computing';
496 $topic5->name = 'christmas';
497 // Add one page to the book
498 $book->ownPage[] = $page1;
499 $id = R::store( $book );
500 asrt( count( $book->ownPage ), 1 );
501 asrt( reset( $book->ownPage )->getMeta( 'type' ), 'page' );
502 $book = R::load( 'book', $id );
503 asrt( count( $book->ownPage ), 1 );
504 asrt( reset( $book->ownPage )->getMeta( 'type' ), 'page' );
505 // Performing an own addition
506 $book->ownPage[] = $page2;
507 $id = R::store( $book );
508 $book = R::load( 'book', $id );
509 asrt( count( $book->ownPage ), 2 );
510 // Performing a deletion
511 $book = R::load( 'book', $id );
512 unset( $book->ownPage[1] );
513 $id = R::store( $book );
514 $book = R::load( 'book', $id );
515 asrt( count( $book->ownPage ), 1 );
516 asrt( reset( $book->ownPage )->getMeta( 'type' ), 'page' );
517 asrt( R::count( 'page' ), 2 ); //still exists
518 asrt( reset( $book->ownPage )->id, '2' );
519 // Doing a change in one of the owned items
520 $book->ownPage[2]->title = 'page II';
521 $id = R::store( $book );
522 $book = R::load( 'book', $id );
523 asrt( reset( $book->ownPage )->title, 'page II' );
524 // Change by reference now... don't copy!
525 $refToPage2 = $book->ownPage[2];
526 $refToPage2->title = 'page II b';
527 $id = R::store( $book );
528 $book = R::load( 'book', $id );
529 asrt( reset( $book->ownPage )->title, 'page II b' );
530 // Doing all actions combined
531 $book->ownPage[] = $page3;
533 $book = R::load( 'book', $id );
534 unset( $book->ownPage[2] );
535 // And test custom key
536 $book->ownPage['customkey'] = $page4;
537 $book->ownPage[3]->title = "THIRD";
539 $book = R::load( 'book', $id );
540 asrt( count( $book->ownPage ), 2 );
541 $p4 = $book->ownPage[4];
542 $p3 = $book->ownPage[3];
543 asrt( $p4->title, 'pagina4' );
544 asrt( $p3->title, 'THIRD' );
545 // Test replacing an element
546 $book = R::load( 'book', $id );
547 $book->ownPage[4] = $page5;
549 $book = R::load( 'book', $id );
550 asrt( count( $book->ownPage ), 2 );
551 $p5 = $book->ownPage[5];
552 asrt( $p5->title, 'pagina5' );
553 // Other way around - single bean
554 asrt( $p5->book->title, 'abc' );
555 asrt( R::load( 'page', 5 )->book->title, 'abc' );
556 asrt( R::load( 'page', 3 )->book->title, 'abc' );
557 // Add the other way around - single bean
559 $page1->book = $book2;
560 $page1 = R::load( 'page', R::store( $page1 ) );
561 asrt( $page1->book->title, 'def' );
562 $b2 = R::load( 'book', $id );
563 asrt( count( $b2->ownPage ), 2 );
564 // Remove the other way around - single bean
565 unset( $page1->book );
567 $b2 = R::load( 'book', $book2->id );
568 asrt( count( $b2->ownPage ), 1 ); //does not work
571 $b2 = R::load( 'book', $book2->id );
572 asrt( count( $b2->ownPage ), 0 ); //works
574 $b2->ownPage[] = $page1;
576 $b2 = R::load( 'book', $book2->id );
577 asrt( count( $b2->ownPage ), 1 );
578 // Different, less elegant way to remove
579 $page1 = reset( $b2->ownPage );
580 $page1->book_id = NULL;
582 $b2 = R::load( 'book', $book2->id );
583 asrt( count( $b2->ownPage ), 0 );
585 $b2->ownPage[] = $page1;
587 $b2 = R::load( 'book', $book2->id );
588 asrt( count( $b2->ownPage ), 1 );
589 // Another less elegant way to remove
592 $cols = R::getColumns( 'page' );
593 asrt( isset( $cols['book'] ), FALSE );
594 $b2 = R::load( 'book', $book2->id );
595 asrt( count( $b2->ownPage ), 0 );
597 $b2->ownPage[] = $page1;
599 $b2 = R::load( 'book', $book2->id );
600 asrt( count( $b2->ownPage ), 1 );
601 // Another less elegant... just plain ugly... way to remove
602 $page1->book = FALSE;
604 $cols = R::getColumns( 'page' );
605 asrt( isset( $cols['book'] ), FALSE );
606 $b2 = R::load( 'book', $book2->id );
607 asrt( count( $b2->ownPage ), 0 );
609 $b2->ownPage[] = $page1;
611 $b2 = R::load( 'book', $book2->id );
612 asrt( count( $b2->ownPage ), 1 );
613 // You are not allowed to re-use the field for something else
617 TRUE, 'NULL', new \stdClass,
618 'just a string', array( 'a' => 1 ), 0
622 $page1->book = $value;
624 } catch ( RedException $e ) {
628 // Test fk, not allowed to set to 0
629 $page1 = reset( $b2->ownPage );
631 // Even uglier way, but still needs to work
632 $page1 = reset( $b2->ownPage );
633 $page1->book_id = NULL;
635 $b2 = R::load( 'book', $book2->id );
636 asrt( count( $b2->ownPage ), 0 );
638 $book = R::load( 'book', $id );
639 $book->sharedTopic[] = $topic1;
640 $id = R::store( $book );
642 asrt( count( $book->sharedTopic ), 1 );
643 asrt( reset( $book->sharedTopic )->name, 'holiday' );
644 $book = R::load( 'book', $id );
645 asrt( count( $book->sharedTopic ), 1 );
646 asrt( reset( $book->sharedTopic )->name, 'holiday' );
648 $book->sharedTopic[] = $topic2;
649 $id = R::store( $book );
650 $tidx = R::store( R::dispense( 'topic' ) );
651 $book = R::load( 'book', $id );
652 asrt( count( $book->sharedTopic ), 2 );
653 $t1 = $book->sharedTopic[1];
654 $t2 = $book->sharedTopic[2];
655 asrt( $t1->name, 'holiday' );
656 asrt( $t2->name, 'cooking' );
658 unset( $book->sharedTopic[2] );
659 asrt( count( $book->sharedTopic ), 1 );
660 $id = R::store( $book );
661 $book = R::load( 'book', $id );
662 asrt( count( $book->sharedTopic ), 1 );
663 asrt( reset( $book->sharedTopic )->name, 'holiday' );
665 $book->sharedTopic[] = $topic3;
666 $book->sharedTopic[1]->name = 'tropics';
667 $id = R::store( $book );
668 $book = R::load( 'book', $id );
669 asrt( count( $book->sharedTopic ), 2 );
670 asrt( $book->sharedTopic[1]->name, 'tropics' );
671 testids( $book->sharedTopic );
672 R::trash( R::load( 'topic', $tidx ) );
673 $id = R::store( $book );
674 $book = R::load( 'book', $id );
675 // Delete without save
676 unset( $book->sharedTopic[1] );
677 $book = R::load( 'book', $id );
678 asrt( count( $book->sharedTopic ), 2 );
679 $book = R::load( 'book', $id );
680 // Delete without init
681 asrt( ( R::count( 'topic' ) ), 3 );
682 unset( $book->sharedTopic[1] );
683 $id = R::store( $book );
684 asrt( ( R::count( 'topic' ) ), 3 );
685 asrt( count( $book->sharedTopic ), 1 );
686 asrt( count( $book2->sharedTopic ), 0 );
687 // Add same topic to other book
688 $book2->sharedTopic[] = $topic3;
689 asrt( count( $book2->sharedTopic ), 1 );
690 $id2 = R::store( $book2 );
691 asrt( count( $book2->sharedTopic ), 1 );
692 $book2 = R::load( 'book', $id2 );
693 asrt( count( $book2->sharedTopic ), 1 );
694 // Get books for topic
695 asrt( $topic3->countShared('book'), 2 );
696 $t3 = R::load( 'topic', $topic3->id );
697 asrt( count( $t3->sharedBook ), 2 );
698 // Nuke an own-array, replace entire array at once without getting first
700 $page2->title = 'yet another page 2';
702 $page4->title = 'yet another page 4';
703 $book = R::load( 'book', $id );
704 $book->ownPage = array( $page2, $page4 );
706 $book = R::load( 'book', $id );
707 asrt( count( $book->ownPage ), 2 );
708 asrt( reset( $book->ownPage )->title, 'yet another page 2' );
709 asrt( end( $book->ownPage )->title, 'yet another page 4' );
710 testids( $book->ownPage );
711 // Test with alias format
712 $book3->cover = $page6;
713 $idb3 = R::store( $book3 );
714 $book3 = R::load( 'book', $idb3 );
715 $justACover = $book3->fetchAs( 'page' )->cover;
716 asrt( ( $book3->cover instanceof OODBBean ), TRUE );
717 asrt( $justACover->title, 'cover1' );
719 asrt( isset( $book3->page ), FALSE );
720 // Test doubling and other side effects ... should not occur..
721 $book3->sharedTopic = array( $topic1, $topic2 );
722 $book3 = R::load( 'book', R::store( $book3 ) );
723 $book3->sharedTopic = array();
724 $book3 = R::load( 'book', R::store( $book3 ) );
725 asrt( count( $book3->sharedTopic ), 0 );
726 $book3->sharedTopic[] = $topic1;
727 $book3 = R::load( 'book', R::store( $book3 ) );
728 // Added only one, not more?
729 asrt( count( $book3->sharedTopic ), 1 );
730 asrt( intval( R::getCell( "select count(*) from book_topic where book_id = $idb3" ) ), 1 );
732 $book3->sharedTopic[] = $topic1;
733 $book3 = R::load( 'book', R::store( $book3 ) );
734 asrt( count( $book3->sharedTopic ), 1 );
735 asrt( intval( R::getCell( "select count(*) from book_topic where book_id = $idb3" ) ), 1 );
736 $book3->sharedTopic['differentkey'] = $topic1;
737 $book3 = R::load( 'book', R::store( $book3 ) );
738 asrt( count( $book3->sharedTopic ), 1 );
739 asrt( intval( R::getCell( "select count(*) from book_topic where book_id = $idb3" ) ), 1 );
740 // Ugly assign, auto array generation
741 $book3->ownPage[] = $page1;
742 $book3 = R::load( 'book', R::store( $book3 ) );
743 asrt( count( $book3->ownPage ), 1 );
744 asrt( intval( R::getCell( "select count(*) from page where book_id = $idb3 " ) ), 1 );
745 $book3 = R::load( 'book', $idb3 );
746 $book3->ownPage = array();
747 // No change until saved
748 asrt( intval( R::getCell( "select count(*) from page where book_id = $idb3 " ) ), 1 );
749 $book3 = R::load( 'book', R::store( $book3 ) );
750 asrt( intval( R::getCell( "select count(*) from page where book_id = $idb3 " ) ), 0 );
751 asrt( count( $book3->ownPage ), 0 );
752 $book3 = R::load( 'book', $idb3 );
754 * Why do I need to do this ---> why does trash() not set id -> 0?
755 * Because you unset() so trash is done on origin not bean
760 $book3->ownPage[] = $page1;
761 $book3->ownPage[] = $page2;
762 $book3->ownPage[] = $page3;
763 $book3 = R::load( 'book', R::store( $book3 ) );
764 asrt( intval( R::getCell( "select count(*) from page where book_id = $idb3 " ) ), 3 );
765 asrt( count( $book3->ownPage ), 3 );
766 unset( $book3->ownPage[$page2->id] );
767 $book3->ownPage[] = $page3;
768 $book3->ownPage['try_to_trick_ya'] = $page3;
769 $book3 = R::load( 'book', R::store( $book3 ) );
770 asrt( intval( R::getCell( "select count(*) from page where book_id = $idb3 " ) ), 2 );
771 asrt( count( $book3->ownPage ), 2 );
773 $book3 = R::load( 'book', $idb3 );
774 unset( $book3->ownPage[10] );
775 $book3->ownPage[] = $page1;
776 $book3 = R::load( 'book', R::store( $book3 ) );
777 asrt( count( $book3->ownPage ), 2 );
778 $book3 = R::load( 'book', $idb3 );
779 unset( $book3->sharedTopic[1] );
780 $book3->sharedTopic[] = $topic1;
781 $book3 = R::load( 'book', R::store( $book3 ) );
782 asrt( count( $book3->sharedTopic ), 1 );
784 $logger = R::debug( true, 1 );
785 $book = R::load( 'book', 1 );
786 $book->sharedTopic = array();
788 // No more than 1 update
789 asrt( count( $logger->grep( 'UPDATE' ) ), 1 );
790 $book = R::load( 'book', 1 );
792 print_r( $book->sharedTopic, 1 );
793 // No more than 1 select
794 asrt( count( $logger->grep( 'SELECT' ) ), 1 );
796 $book->sharedTopic[] = $topic1;
797 $book->sharedTopic[] = $topic2;
798 asrt( count( $logger->grep( 'SELECT' ) ), 0 );
800 $book->sharedTopic[] = $topic3;
801 // Now do NOT clear all and then add one, just add the one
804 $book = R::load( 'book', 1 );
805 asrt( count( $book->sharedTopic ), 3 );
807 asrt( count( $logger->grep( "DELETE FROM" ) ), 0 );
808 $book->sharedTopic['a'] = $topic3;
809 unset( $book->sharedTopic['a'] );
811 $book = R::load( 'book', 1 );
812 asrt( count( $book->sharedTopic ), 3 );
814 asrt( count( $logger->grep( "DELETE FROM" ) ), 0 );
815 $book->ownPage = array();
817 asrt( count( $book->ownPage ), 0 );
818 $book->ownPage[] = $page1;
819 $book->ownPage['a'] = $page2;
820 asrt( count( $book->ownPage ), 2 );
822 unset( $book->ownPage['a'] );
823 asrt( count( $book->ownPage ), 2 );
824 unset( $book->ownPage[11] );
826 $book = R::load( 'book', 1 );
827 asrt( count( $book->ownPage ), 1 );
828 $aPage = $book->ownPage[10];
829 unset( $book->ownPage[10] );
830 $aPage->title .= ' changed ';
831 $book->ownPage['anotherPage'] = $aPage;
834 $book = R::load( 'book', 1 );
835 asrt( count( $book->ownPage ), 1 );
836 $ap = reset( $book->ownPage );
837 asrt( $ap->title, "pagina1 changed " );
838 // Fix udiff instead of diff
839 $book3->ownPage = array( $page3, $page1 );
840 $i = R::store( $book3 );
841 $book3 = R::load( 'book', $i );
842 asrt( intval( R::getCell( "select count(*) from page where book_id = $idb3 " ) ), 2 );
843 asrt( count( $book3->ownPage ), 2 );
848 $book3->ownPicture[] = $pic1;
849 $book3->ownQuote[] = $q1;
850 $book3 = R::load( 'book', R::store( $book3 ) );
851 // two own-arrays -->forgot array_merge
852 asrt( count( $book3->ownPicture ), 1 );
853 asrt( count( $book3->ownQuote ), 1 );
854 asrt( count( $book3->ownPage ), 2 );
855 $book3 = R::load( 'book', R::store( $book3 ) );
856 unset( $book3->ownPicture[1] );
857 $book3 = R::load( 'book', R::store( $book3 ) );
858 asrt( count( $book3->ownPicture ), 0 );
859 asrt( count( $book3->ownQuote ), 1 );
860 asrt( count( $book3->ownPage ), 2 );
861 $book3 = R::load( 'book', R::store( $book3 ) );
863 $quotes = R::dispense( 'quote', 10 );
864 foreach ( $quotes as &$justSomeQuote ) {
865 $justSomeQuote->note = 'note' . ( ++$NOTE );
867 $pictures = R::dispense( 'picture', 10 );
868 foreach ( $pictures as &$justSomePic ) {
869 $justSomePic->note = 'note' . ( ++$NOTE );
871 $topics = R::dispense( 'topic', 10 );
872 foreach ( $topics as &$justSomeTopic ) {
873 $justSomeTopic->note = 'note' . ( ++$NOTE );
875 for ( $j = 0; $j < 10; $j++ ) {
876 // Do several mutations
877 for ( $x = 0; $x < rand( 1, 20 ); $x++ ) {
878 modgr( $book3, $quotes, $pictures, $topics );
880 $qbefore = count( $book3->ownQuote );
881 $pbefore = count( $book3->ownPicture );
882 $tbefore = count( $book3->sharedTopic );
883 $qjson = json_encode( $book->ownQuote );
884 $pjson = json_encode( $book->ownPicture );
885 $tjson = json_encode( $book->sharedTopic );
886 $book3 = R::load( 'book', R::store( $book3 ) );
887 asrt( count( $book3->ownQuote ), $qbefore );
888 asrt( count( $book3->ownPicture ), $pbefore );
889 asrt( count( $book3->sharedTopic ), $tbefore );
890 asrt( json_encode( $book->ownQuote ), $qjson );
891 asrt( json_encode( $book->ownPicture ), $pjson );
892 asrt( json_encode( $book->sharedTopic ), $tjson );
893 testids( $book->ownQuote );
894 testids( $book->ownPicture );
895 testids( $book->sharedTopic );
900 * Test parent bean relations.
904 public function testParentBean()
906 $village = R::dispense( 'village' );
907 $village->name = 'village';
908 $home = R::dispense( 'building' );
909 $home->village = $village;
910 $id = R::store( $home );
911 $home = R::load( 'building', $id );
912 asrt( $home->village->name, 'village' );
913 asrt( R::count( 'village' ), 1 );
914 asrt( R::count( 'building' ), 1 );
917 asrt( R::count( 'village' ), 1 );
918 asrt( R::count( 'building' ), 0 );
922 * test N-M relations through intermediate beans
926 public function testNMRelationsIntermediate()
928 list( $mrA, $mrB, $mrC ) = R::dispense( 'person', 3 );
929 list( $projA, $projB, $projC ) = R::dispense( 'project', 3 );
933 $participant = R::dispense( 'participant' );
934 $projA->link( 'participant', array( 'role' => 'manager' ) )->person = $mrA;
935 $projA->link( $participant->setAttr( 'role', 'developer' ) )->person = $mrB;
936 $projB->link( R::dispense( 'participant' )->setAttr( 'role', 'developer' ) )->person = $mrB;
937 $projB->link( 'participant', '{"role":"helpdesk"}' )->person = $mrC;
938 $projC->link( 'participant', '{"role":"sales"}' )->person = $mrC;
939 R::storeAll( array( $projA, $projB, $projC ) );
940 $a = R::findOne( 'project', ' title = ? ', array( 'A' ) );
941 $b = R::findOne( 'project', ' title = ? ', array( 'B' ) );
942 $c = R::findOne( 'project', ' title = ? ', array( 'C' ) );
943 asrt( count( $a->ownParticipant ), 2 );
944 asrt( count( $b->ownParticipant ), 2 );
945 asrt( count( $c->ownParticipant ), 1 );
946 $managers = $developers = 0;
947 foreach ( $a->ownParticipant as $p ) {
948 if ( $p->role === 'manager' ) {
951 if ( $p->role === 'developer' ) {
955 $p = reset( $a->ownParticipant );
956 asrt( $p->person->getMeta( 'type' ), 'person' );
957 asrt( ( $p->person->id > 0 ), TRUE );
958 asrt( $managers, 1 );
959 asrt( $developers, 1 );
960 asrt( (int) R::count( 'participant' ), 5 );
961 asrt( (int) R::count( 'person' ), 3 );
965 * test emulation of sharedList through intermediate beans
969 public function testSharedListIntermediate()
971 list( $v1, $v2, $v3 ) = R::dispense( 'village', 3 );
972 list( $a1, $a2, $a3 ) = R::dispense( 'army', 3 );
976 $v1->name = 'Ville 1';
977 $v2->name = 'Ville 2';
978 $v3->name = 'Ville 3';
979 $v1->link( 'armyVillage' )->army = $a3;
980 $v2->link( 'army_village' )->army = $a2;
981 $v3->link( 'armyVillage' )->army = $a1;
982 $a2->link( 'army_village' )->village = $v1;
983 $id1 = R::store( $v1 );
984 $id2 = R::store( $v2 );
985 $id3 = R::store( $v3 );
986 $village1 = R::load( 'village', $id1 );
987 $village2 = R::load( 'village', $id2 );
988 $village3 = R::load( 'village', $id3 );
989 asrt( count( $village1->sharedArmy ), 2 );
990 asrt( count( $village2->sharedArmy ), 1 );
991 asrt( count( $village3->sharedArmy ), 1 );
995 * test emulation via association renaming
999 public function testAssociationRenaming()
1001 list( $p1, $p2, $p3 ) = R::dispense( 'painting', 3 );
1002 list( $m1, $m2, $m3 ) = R::dispense( 'museum', 3 );
1003 $p1->name = 'painting1';
1004 $p2->name = 'painting2';
1005 $p3->name = 'painting3';
1009 R::renameAssociation( 'museum_painting', 'exhibited' );
1010 // Also test array syntax
1011 R::renameAssociation( array( 'museum_museum' => 'center' ) );
1012 $m1->link( 'center', array( 'name' => 'History Center' ) )->museum2 = $m2;
1013 $m1->link( 'exhibited', '{"from":"2014-02-01","til":"2014-07-02"}' )->painting = $p3;
1014 $m2->link( 'exhibited', '{"from":"2014-07-03","til":"2014-10-02"}' )->painting = $p3;
1015 $m3->link( 'exhibited', '{"from":"2014-02-01","til":"2014-07-02"}' )->painting = $p1;
1016 $m2->link( 'exhibited', '{"from":"2014-02-01","til":"2014-07-02"}' )->painting = $p2;
1017 R::storeAll( array( $m1, $m2, $m3 ) );
1018 list( $m1, $m2, $m3 ) = array_values( R::findAll( 'museum', ' ORDER BY thename ASC' ) );
1019 asrt( count( $m1->sharedMuseum ), 1 );
1020 asrt( count( $m1->sharedPainting ), 1 );
1021 asrt( count( $m2->sharedPainting ), 2 );
1022 asrt( count( $m3->sharedPainting ), 1 );
1023 $p3 = reset( $m1->sharedPainting );
1024 asrt( count( $p3->ownExhibited ), 2 );
1025 asrt( count( $m2->ownExhibited ), 2 );
1026 R::storeAll( array( $m1, $m2, $m3 ) );
1027 list( $m1, $m2, $m3 ) = array_values( R::findAll( 'museum', ' ORDER BY thename ASC' ) );
1028 asrt( count( $m1->sharedPainting ), 1 );
1029 asrt( count( $m2->sharedPainting ), 2 );
1030 asrt( count( $m3->sharedPainting ), 1 );
1031 $p3 = reset( $m1->sharedPainting );
1032 asrt( count( $p3->ownExhibited ), 2 );
1033 $paintings = $m2->sharedPainting;
1034 foreach ( $paintings as $painting ) {
1035 if ( $painting->name === 'painting2' ) {
1037 $paintingX = $painting;
1040 unset( $m2->sharedPainting[$paintingX->id] );
1042 $m2 = R::load( 'museum', $m2->id );
1043 asrt( count( $m2->sharedPainting ), 1 );
1044 $left = reset( $m2->sharedPainting );
1045 asrt( $left->name, 'painting3' );
1046 asrt( count( $m2->ownExhibited ), 1 );
1047 $exhibition = reset( $m2->ownExhibited );
1048 asrt( $exhibition->from, '2014-07-03' );
1049 asrt( $exhibition->til, '2014-10-02' );
1053 * Test don't try to store other things in shared list.
1057 public function testDontTryToStoreOtherThingsInSharedList() {
1059 $book = R::dispense( 'book' );
1060 $book->sharedPage[] = 'nonsense';
1064 } catch( RedException $exception) {
1067 $book->sharedPageList = R::dispense( 'page', 2 );
1069 $book->sharedPageList;
1071 asrt( R::count('page'), 2 );
1075 * Test whether magic array interface functions like isset() and
1076 * unset work correctly with the x-own-list and the List-suffix.
1078 * Array functions do not reveal x-own-lists and list-alias because
1079 * you dont want duplicate entries in foreach-loops.
1080 * Also offers a slight performance improvement for array access.
1084 public function testWhetherIssetWorksWithXList()
1087 $book = R::dispense( 'book' );
1088 $page = R::dispense( 'page' );
1089 asrt( isset( $book->xownPageList ), FALSE );
1090 asrt( isset( $book->ownPageList ), FALSE );
1091 asrt( isset( $book->xownPage ), FALSE );
1092 asrt( isset( $book->ownPage ), FALSE );
1093 $book->xownPageList[] = $page;
1094 asrt( isset( $book->xownPageList ), TRUE );
1095 asrt( isset( $book->ownPageList ), TRUE );
1096 asrt( isset( $book->xownPage ), TRUE );
1097 asrt( isset( $book->ownPage ), TRUE );
1099 asrt( isset( $book['xownPageList'] ), TRUE );
1100 asrt( isset( $book['ownPageList'] ), TRUE );
1101 asrt( isset( $book['xownPage'] ), TRUE );
1102 asrt( isset( $book['ownPage'] ), TRUE );
1104 $book = $book->fresh();
1105 asrt( isset( $book->xownPageList ), FALSE );
1106 asrt( isset( $book->ownPageList ), FALSE );
1107 asrt( isset( $book->xownPage ), FALSE );
1108 asrt( isset( $book->ownPage ), FALSE );
1109 asrt( isset( $book['xownPageList'] ), FALSE );
1110 asrt( isset( $book['ownPageList'] ), FALSE );
1111 asrt( isset( $book['xownPage'] ), FALSE );
1112 asrt( isset( $book['ownPage'] ), FALSE );
1113 $book->xownPageList;
1114 asrt( isset( $book->xownPageList ), TRUE );
1115 asrt( isset( $book->ownPageList ), TRUE );
1116 asrt( isset( $book->xownPage ), TRUE );
1117 asrt( isset( $book->ownPage ), TRUE );
1118 asrt( isset( $book['xownPageList'] ), TRUE );
1119 asrt( isset( $book['ownPageList'] ), TRUE );
1120 asrt( isset( $book['xownPage'] ), TRUE );
1121 asrt( isset( $book['ownPage'] ), TRUE );
1122 $book = $book->fresh();
1123 asrt( isset( $book->xownPageList ), FALSE );
1124 asrt( isset( $book->ownPageList ), FALSE );
1125 asrt( isset( $book->xownPage ), FALSE );
1126 asrt( isset( $book->ownPage ), FALSE );
1127 asrt( isset( $book['xownPageList'] ), FALSE );
1128 asrt( isset( $book['ownPageList'] ), FALSE );
1129 asrt( isset( $book['xownPage'] ), FALSE );
1130 asrt( isset( $book['ownPage'] ), FALSE );
1131 $book->noLoad()->xownPageList;
1132 asrt( isset( $book->xownPageList ), TRUE );
1133 asrt( isset( $book->ownPageList ), TRUE );
1135 asrt( count( $book->ownPageList ), 0 );
1136 asrt( count( $book->xownPageList ), 0 );
1137 asrt( count( $book->ownPage ), 0 );
1138 asrt( count( $book->xownPage ), 0 );
1139 $book->xownPageList[] = $page;
1140 asrt( isset( $book->xownPageList ), TRUE );
1141 asrt( isset( $book->ownPageList ), TRUE );
1142 asrt( isset( $book->xownPage ), TRUE );
1143 asrt( isset( $book->ownPage ), TRUE );
1144 asrt( isset( $book['xownPageList'] ), TRUE );
1145 asrt( isset( $book['ownPageList'] ), TRUE );
1146 asrt( isset( $book['xownPage'] ), TRUE );
1147 asrt( isset( $book['ownPage'] ), TRUE );
1148 unset( $book->xownPageList );
1149 asrt( isset( $book->xownPageList ), FALSE );
1150 asrt( isset( $book->ownPageList ), FALSE );
1151 asrt( isset( $book->xownPage ), FALSE );
1152 asrt( isset( $book->ownPage ), FALSE );
1153 asrt( isset( $book['xownPageList'] ), FALSE );
1154 asrt( isset( $book['ownPageList'] ), FALSE );
1155 asrt( isset( $book['xownPage'] ), FALSE );
1156 asrt( isset( $book['ownPage'] ), FALSE );
1157 $book->xownPageList[] = $page;
1158 asrt( isset( $book->xownPageList ), TRUE );
1159 asrt( isset( $book->ownPageList ), TRUE );
1160 asrt( isset( $book->xownPage ), TRUE );
1161 asrt( isset( $book->ownPage ), TRUE );
1162 asrt( isset( $book['xownPageList'] ), TRUE );
1163 asrt( isset( $book['ownPageList'] ), TRUE );
1164 asrt( isset( $book['xownPage'] ), TRUE );
1165 asrt( isset( $book['ownPage'] ), TRUE );
1166 unset( $book->xownPage );
1167 asrt( isset( $book->xownPageList ), FALSE );
1168 asrt( isset( $book->ownPageList ), FALSE );
1169 asrt( isset( $book->xownPage ), FALSE );
1170 asrt( isset( $book->ownPage ), FALSE );
1171 asrt( isset( $book['xownPageList'] ), FALSE );
1172 asrt( isset( $book['ownPageList'] ), FALSE );
1173 asrt( isset( $book['xownPage'] ), FALSE );
1174 asrt( isset( $book['ownPage'] ), FALSE );
1175 $book = $book->fresh();
1176 asrt( isset( $book->xownPageList ), FALSE );
1177 asrt( isset( $book->ownPageList ), FALSE );
1178 asrt( isset( $book->xownPage ), FALSE );
1179 asrt( isset( $book->ownPage ), FALSE );
1180 asrt( isset( $book['xownPageList'] ), FALSE );
1181 asrt( isset( $book['ownPageList'] ), FALSE );
1182 asrt( isset( $book['xownPage'] ), FALSE );
1183 asrt( isset( $book['ownPage'] ), FALSE );
1185 asrt( isset( $book->xownPageList ), TRUE );
1186 asrt( isset( $book->ownPageList ), TRUE );
1187 asrt( isset( $book->xownPage ), TRUE );
1188 asrt( isset( $book->ownPage ), TRUE );
1189 asrt( isset( $book['xownPageList'] ), TRUE );
1190 asrt( isset( $book['ownPageList'] ), TRUE );
1191 asrt( isset( $book['xownPage'] ), TRUE );
1192 asrt( isset( $book['ownPage'] ), TRUE );
1196 * Test whether you can still set items starting with 'xown' or
1197 * 'own' not followed by an uppercase character.
1201 public function testConfusionWithXOwnList()
1203 $book = R::dispense( 'book' );
1204 $book->xownitem = 1;
1205 asrt( isset( $book->xownitem ), TRUE );
1206 asrt( (int) $book->xownitem, 1 );
1207 asrt( isset( $book->xownItem ), FALSE );
1208 asrt( isset( $book->xownItemList ), FALSE );
1210 asrt( isset( $book->ownitem ), TRUE );
1211 asrt( (int) $book->ownitem, 1 );
1212 asrt( isset( $book->ownItemList ), FALSE );
1214 $book = $book->fresh();
1215 asrt( isset( $book->xownitem ), TRUE );
1216 asrt( (int) $book->xownitem, 1 );
1217 asrt( isset( $book->xownItem ), FALSE );
1218 asrt( isset( $book->xownItemList ), FALSE );
1219 asrt( isset( $book->ownitem ), TRUE );
1220 asrt( (int) $book->ownitem, 1 );
1221 asrt( isset( $book->ownItemList ), FALSE );
1225 * Test whether we can determine the mode of a list.
1229 public function testModeCheckerOfLists()
1231 foreach( array( 'ownPage', 'xownPage', 'ownPageList', 'xownPageList' ) as $listName ) {
1232 $book = R::dispense( 'book' );
1233 asrt( $book->isListInExclusiveMode( $listName ), FALSE );
1234 $book->ownPageList[] = R::dispense( 'page' );
1235 asrt( $book->isListInExclusiveMode( $listName ), FALSE );
1236 $book = R::dispense( 'book' );
1237 asrt( $book->isListInExclusiveMode( $listName ), FALSE );
1238 $book->xownPageList[] = R::dispense( 'page' );
1239 asrt( $book->isListInExclusiveMode( $listName ), TRUE );
1240 $book = R::dispense( 'book' );
1241 asrt( $book->isListInExclusiveMode( $listName ), FALSE );
1242 $book->ownPage[] = R::dispense( 'page' );
1243 asrt( $book->isListInExclusiveMode( $listName ), FALSE );
1244 $book = R::dispense( 'book' );
1245 asrt( $book->isListInExclusiveMode( $listName ), FALSE );
1246 $book->xownPage[] = R::dispense( 'page' );
1247 asrt( $book->isListInExclusiveMode( $listName ), TRUE );