3 namespace RedUNIT\Base;
5 use RedUNIT\Base as Base;
6 use RedBeanPHP\Facade as R;
11 * With/WithCondition can be used to fetch bean lists with additional
12 * requirements, filters or ordering specification using SQL snippets.
13 * This suite tests the handling of with() and withCondition() snippets.
14 * Additionally this test suite also tests noLoad() and all() modifiers.
16 * @file RedUNIT/Base/With.php
17 * @desc Tests query modification of own-lists with prefix-with
18 * @author Gabor de Mooij and the RedBeanPHP Community
19 * @license New BSD/GPLv2
21 * (c) G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community.
22 * This source file is subject to the New BSD/GPLv2 License that is bundled
23 * with this source code in the file license.txt.
25 class With extends Base
29 * This test suite uses specific SQL, only suited for MySQL.
33 public function getTargetDrivers()
35 return array( 'mysql' );
39 * Tests no-load modifier for lists.
43 public function testNoLoad()
45 $book = R::dispense( array(
47 'title' => 'Book of Lorem Ipsum',
51 'content' => 'Lorem Ipsum',
62 $book = $book->fresh();
63 asrt( R::count( 'book' ), 1 );
64 asrt( count( $book->ownPage ), 1 );
65 //now try with no-load
66 $book = $book->fresh();
67 asrt( count( $book->noLoad()->ownPage ), 0 );
68 asrt( count( $book->noLoad()->sharedTag ), 0 );
69 //now try to add with no-load
70 $book = $book->fresh();
71 $book->noLoad()->xownPageList[] = R::dispense( 'page' );
72 $book->noLoad()->sharedTagList[] = R::dispense( 'tag' );
74 $book = $book->fresh();
75 asrt( count( $book->ownPage ), 2 );
76 asrt( count( $book->sharedTagList ), 2 );
77 //no-load overrides with and withCondition
78 $book = $book->fresh();
79 asrt( count( $book->with(' invalid sql ')->noLoad()->ownPage ), 0 );
80 asrt( count( $book->withCondition(' invalid sql ')->noLoad()->sharedTag ), 0 );
81 //no-load overrides all and alias
82 $book = $book->fresh();
83 asrt( count( $book->all()->noLoad()->ownPage ), 0 );
84 asrt( count( $book->alias('nothing')->noLoad()->sharedTag ), 0 );
85 //no-load gets cleared
86 $book = $book->fresh();
87 asrt( count( $book->ownPage ), 2 );
88 asrt( count( $book->sharedTagList ), 2 );
89 //We cant clear with no-load accidentally?
90 $book = $book->fresh();
91 $book->noLoad()->ownPage = array();
92 $book->noLoad()->sharedTagList = array();
94 asrt( count( $book->ownPage ), 2 );
95 asrt( count( $book->sharedTagList ), 2 );
96 //No-load does not have effect if list is already cached
97 $book = $book->fresh();
100 asrt( count( $book->ownPage ), 2 );
101 asrt( count( $book->sharedTagList ), 2 );
109 public function testAll()
111 $book = R::dispense( 'book' );
112 $book->ownPage = R::dispense( 'page', 10 );
114 asrt( count( $book->with( ' LIMIT 3 ' )->ownPage ), 3 );
115 asrt( count( $book->ownPage ), 3 );
116 asrt( count( $book->all()->ownPage ), 10 );
117 asrt( count( $book->ownPage ), 10 );
119 asrt( count( $book->ownPage ), 10 );
120 asrt( count( $book->all()->ownPage ), 0 );
124 * Test embedded SQL snippets using with and withCondition.
128 public function testEmbeddedSQL()
130 list( $page1, $page2, $page3 ) = R::dispense( 'page', 3 );
131 list( $ad1, $ad2, $ad3 ) = R::dispense( 'ad', 3 );
132 $ad2->name = 'shampoo';
133 $page3->name = 'homepage';
134 $page1->sharedAd = array( $ad1, $ad3 );
135 $page2->sharedAd = array( $ad2, $ad3 );
136 $page3->sharedAd = array( $ad3, $ad2, $ad1 );
137 R::storeAll( array( $page1, $page2, $page3 ) );
138 $page1 = R::load( 'page', $page1->id );
139 asrt( 1, count( $page1->with( ' LIMIT 1 ' )->sharedAd ) );
140 $page2 = R::load( 'page', $page2->id );
141 $adsOnPage2 = $page2->withCondition( ' `name` = ? ', array( 'shampoo' ) )->sharedAd;
142 asrt( 1, count( $adsOnPage2 ) );
143 $ad = reset( $adsOnPage2 );
144 asrt( $ad->name, 'shampoo' );
145 $ad = R::load( 'ad', $ad->id );
146 asrt( count( $ad->sharedPage ), 2 );
147 $ad = R::load( 'ad', $ad->id );
148 $homepage = reset( $ad->withCondition( ' `name` LIKE ? AND page.id > 0 ORDER BY id DESC ', array( '%ome%' ) )->sharedPage );
149 asrt( $homepage->name, 'homepage' );
157 public function testEmbeddedSQLPart2()
159 list( $book1, $book2, $book3 ) = R::dispense( 'book', 3 );
160 $book1->position = 1;
161 $book2->position = 2;
162 $book3->position = 3;
163 $shelf = R::dispense( 'shelf' );
164 $shelf->ownBook = array( $book1, $book2, $book3 );
165 $id = R::store( $shelf );
166 $shelf = R::load( 'shelf', $id );
167 $books = $shelf->with( ' ORDER BY position ASC ' )->ownBook;
168 $book1 = array_shift( $books );
169 asrt( (int) $book1->position, 1 );
170 $book2 = array_shift( $books );
171 asrt( (int) $book2->position, 2 );
172 $book3 = array_shift( $books );
173 asrt( (int) $book3->position, 3 );
174 $books = $shelf->with( ' ORDER BY position DESC ' )->ownBook;
175 $book1 = array_shift( $books );
176 asrt( (int) $book1->position, 3 );
177 $book2 = array_shift( $books );
178 asrt( (int) $book2->position, 2 );
179 $book3 = array_shift( $books );
180 asrt( (int) $book3->position, 1 );
181 $shelf = R::load( 'shelf', $id );
182 $books = $shelf->with( ' AND position > 2 ' )->ownBook;
183 asrt( count( $books ), 1 );
184 $shelf = R::load( 'shelf', $id );
185 $books = $shelf->with( ' AND position < ? ', array( 3 ) )->ownBook;
186 asrt( count( $books ), 2 );
187 $shelf = R::load( 'shelf', $id );
188 $books = $shelf->with( ' AND position = 1 ' )->ownBook;
189 asrt( count( $books ), 1 );
190 $shelf = R::load( 'shelf', $id );
191 $books = $shelf->withCondition( ' position > -1 ' )->ownBook;
192 asrt( count( $books ), 3 );
193 // With-condition should not affect storing
194 $shelf = R::load( 'shelf', $id );
195 $books = $shelf->with( ' AND position = 1 ' )->ownBook;
196 asrt( count( $books ), 1 );
197 asrt( count( $shelf->ownBook ), 1 );
198 $book = reset( $shelf->ownBook );
199 $book->title = 'Trees and other Poems';
201 $books = $shelf->withCondition( ' position > -1 ' )->ownBook;
202 asrt( count( $books ), 3 );
203 asrt( count( $shelf->ownBook ), 3 );
204 $shelf = R::load( 'shelf', $id );
205 $books = $shelf->with( ' AND position = 1 ' )->ownBook;
206 // Also with trashing -- just trash one!
207 $shelf->ownBook = array();
209 $books = $shelf->withCondition( ' position > -1 ' )->ownBook;
210 asrt( count( $books ), 2 );
211 // With should cause a reload of a list
212 $shelf = R::load( 'shelf', $id );
213 $books = $shelf->with( ' AND position = 2 ' )->ownBook;
214 asrt( count( $books ), 1 );
215 $books = $shelf->withCondition( ' position > -1 ' )->ownBook;
216 asrt( count( $books ), 2 );
217 $book = reset( $books );
218 $book->title = 'Venetian Music';
219 // Should not affect storage (fact that we used with twice, unsetting prop)
221 $shelf = R::load( 'shelf', $id );
222 asrt( count( $shelf->ownBook ), 2 );
224 list( $game1, $game2, $game3 ) = R::dispense( 'game', 3 );
225 list( $t1, $t2, $t3 ) = R::dispense( 'team', 3 );
227 $t2->name = 'Tigers';
228 $t3->name = 'Eagles';
238 R::storeAll( array( $game1, $game2, $game3 ) );
239 $team1 = R::load( 'team', $t1->id );
240 $team2 = R::load( 'team', $t2->id );
241 $team3 = R::load( 'team', $t3->id );
242 asrt( count( $team1->alias( 'team1' )->ownGame ), 2 );
243 asrt( count( $team2->alias( 'team1' )->ownGame ), 1 );
244 $team1 = R::load( 'team', $t1->id );
245 $team2 = R::load( 'team', $t2->id );
246 asrt( count( $team1->alias( 'team2' )->ownGame ), 0 );
247 asrt( count( $team2->alias( 'team2' )->ownGame ), 1 );
248 asrt( count( $team3->alias( 'team1' )->ownGame ), 0 );
249 $team3 = R::load( 'team', $t3->id );
250 asrt( count( $team3->alias( 'team2' )->ownGame ), 2 );
251 $team1 = R::load( 'team', $t1->id );
252 $games = $team1->alias( 'team1' )->ownGame;
253 $game4 = R::dispense( 'game' );
256 $team1->alias( 'team1' )->ownGame[] = $game4;
258 $team1 = R::load( 'team', $t1->id );
259 asrt( count( $team1->alias( 'team1' )->ownGame ), 3 );
260 foreach ( $team1->ownGame as $g ) {
261 if ( $g->name == 'a' ) $game = $g;
263 $game->name = 'match';
265 $team1 = R::load( 'team', $t1->id );
266 asrt( count( $team1->alias( 'team1' )->ownGame ), 3 );
268 foreach ( $team1->ownGame as $g ) {
269 if ( $g->name == 'match' ) $found = 1;
271 if ( $found ) pass();
272 $team1->ownGame = array();
274 $team1 = R::load( 'team', $t1->id );
275 asrt( count( $team1->alias( 'team1' )->ownGame ), 0 );
276 $team1->ownBook[] = $book1;
278 $team1 = R::load( 'team', $t1->id );
279 asrt( count( $team1->alias( 'team1' )->ownGame ), 0 );
280 asrt( count( $team1->ownBook ), 1 );
284 * Test when to reload and when to NOT reload beans.
285 * Use UNSET to reload a parent bean. Use UNSET or
286 * a modifier (with, withCondition, all) to reload a list.
287 * Use noLoad() to obtain an empty list - does not reload
288 * but sets an empty array.
292 public function testWhenToReload()
294 $book = R::dispense( 'book' );
295 $book->ownPage = R::dispense( 'page', 3 );
296 $book->author = R::dispense( 'author' );
297 $book->coauthor = R::dispense( 'author' );
299 $book = $book->fresh();
300 $firstPage = reset( $book->ownPage );
301 $id = $firstPage->id;
302 $book->ownPage[ $id ]->title = 'a';
303 //Do not reload an own list after manipulations
304 asrt( $book->ownPage[ $id ]->title, 'a' ); //dont reload!
305 $book->ownPage[] = R::dispense( 'page' ); //dont reload!
306 asrt( $book->ownPage[ $id ]->title, 'a' ); //dont reload!
307 asrt( $book->ownPageList[ $id ]->title, 'a' ); //dont reload!
308 asrt( $book->xownPageList[ $id ]->title, 'a' ); //dont reload!
309 asrt( $book->xownPage[ $id ]->title, 'a' ); //dont reload!
310 asrt( count( $book->ownPageList ), 4 );
312 unset( $book->ownPageList );
313 asrt( count( $book->ownPageList ), 3 );
314 $book->ownPage[] = R::dispense( 'page' );
315 asrt( count( $book->ownPageList ), 4 );
317 unset( $book->xownPageList );
318 asrt( count( $book->ownPageList ), 3 );
319 $book->ownPage[] = R::dispense( 'page' );
320 asrt( count( $book->ownPageList ), 4 );
322 unset( $book->xownPage );
323 asrt( count( $book->ownPageList ), 3 );
324 $book->ownPage[] = R::dispense( 'page' );
325 asrt( count( $book->ownPageList ), 4 );
327 unset( $book->ownPage );
328 asrt( count( $book->ownPageList ), 3 );
329 $book->ownPage[] = R::dispense( 'page' );
330 asrt( count( $book->ownPageList ), 4 );
332 $book->all()->ownPage;
333 asrt( count( $book->ownPageList ), 3 );
334 $book->ownPage[] = R::dispense( 'page' );
335 asrt( count( $book->ownPageList ), 4 );
337 $book->all()->xownPage;
338 asrt( count( $book->ownPageList ), 3 );
339 $book->ownPage[] = R::dispense( 'page' );
340 asrt( count( $book->ownPageList ), 4 );
342 $book->all()->ownPageList;
343 asrt( count( $book->ownPageList ), 3 );
344 $book->ownPage[] = R::dispense( 'page' );
345 asrt( count( $book->ownPageList ), 4 );
347 $book->all()->xownPageList;
348 asrt( count( $book->ownPageList ), 3 );
349 $book->ownPage[] = R::dispense( 'page' );
350 asrt( count( $book->ownPageList ), 4 );
351 //Do not reload an own list if told to not reload using noLoad()
352 $book->noLoad()->with(' LIMIT 1 ')->ownPage; //dont reload!
353 asrt( count( $book->xownPage ), 0); //dont reload!
354 $book->noLoad()->all()->ownPage; //dont reload!
355 asrt( count( $book->xownPage ), 0); //dont reload!
356 $book->noLoad()->alias('magazine')->ownPage; //dont reload!
357 asrt( count( $book->xownPage ), 0); //dont reload!
358 $book->noLoad()->withCondition('')->ownPage; //dont reload!
359 asrt( count( $book->xownPage ), 0); //dont reload!
360 //even if modifiers proceed noLoad()
361 $book->with(' LIMIT 1 ')->noLoad()->ownPage; //dont reload!
362 asrt( count( $book->xownPage ), 0); //dont reload!
363 $book->all()->noLoad()->ownPage; //dont reload!
364 asrt( count( $book->xownPage ), 0); //dont reload!
365 $book->alias('magazine')->noLoad()->ownPage; //dont reload!
366 asrt( count( $book->xownPage ), 0); //dont reload!
367 $book->withCondition('')->noLoad()->ownPage; //dont reload!
368 asrt( count( $book->xownPage ), 0); //dont reload!
369 //even in combinations
370 $book->all()->with(' LIMIT 1 ')->noLoad()->ownPage; //dont reload!
371 asrt( count( $book->xownPage ), 0); //dont reload!
372 $book->alias('magazine')->all()->noLoad()->ownPage; //dont reload!
373 asrt( count( $book->xownPage ), 0); //dont reload!
374 $book->alias('magazine')->with('LIMIT 1')->noLoad()->ownPage; //dont reload!
375 asrt( count( $book->xownPage ), 0); //dont reload!
376 $book->alias('magazine')->withCondition('')->noLoad()->ownPage; //dont reload!
377 asrt( count( $book->xownPage ), 0); //dont reload!
378 //now test shared list
379 $book->sharedTag = R::dispense( 'tag', 16 );
380 asrt( count( $book->sharedTag ), 16 );
381 $book->sharedTag[] = R::dispense( 'tag' );
382 asrt( count( $book->sharedTag ), 17 ); //dont reload after adding
383 $last = end( $book->sharedTagList );
385 $book->sharedTag[ $id ]->title = 'b';
386 asrt( count( $book->sharedTag ), 17 ); //dont reload after manipulation
387 unset( $book->sharedTagList[ $id ] );
388 asrt( count( $book->sharedTag ), 16 ); //dont reload after manipulation
390 unset( $book->sharedTagList );
391 asrt( count( $book->sharedTag ), 0 );
392 $book->sharedTag = R::dispense( 'tag', 16 );
393 asrt( count( $book->sharedTag ), 16 );
395 unset( $book->sharedTag );
396 asrt( count( $book->sharedTag ), 0 );
397 $book->sharedTag = R::dispense( 'tag', 16 );
398 asrt( count( $book->sharedTag ), 16 );
400 $book->all()->sharedTag;
401 asrt( count( $book->sharedTag ), 0 );
402 $book->sharedTag = R::dispense( 'tag', 16 );
403 asrt( count( $book->sharedTag ), 16 );
405 $book->all()->sharedTagList;
406 asrt( count( $book->sharedTag ), 0 );
407 $book->sharedTag = R::dispense( 'tag', 16 );
408 asrt( count( $book->sharedTag ), 16 );
409 //Do not reload a sharedTag list if told to not reload using noLoad()
410 $book->noLoad()->with(' LIMIT 1 ')->sharedTag; //dont reload!
411 asrt( count( $book->sharedTag ), 0); //dont reload!
412 $book->noLoad()->all()->sharedTag; //dont reload!
413 asrt( count( $book->sharedTag ), 0); //dont reload!
414 $book->noLoad()->alias('magazine')->sharedTag; //dont reload!
415 asrt( count( $book->sharedTag ), 0); //dont reload!
416 $book->noLoad()->withCondition('')->sharedTag; //dont reload!
417 asrt( count( $book->sharedTag ), 0); //dont reload!
418 //even if modifiers proceed noLoad()
419 $book->with(' LIMIT 1 ')->noLoad()->sharedTag; //dont reload!
420 asrt( count( $book->sharedTag ), 0); //dont reload!
421 $book->all()->noLoad()->sharedTag; //dont reload!
422 asrt( count( $book->sharedTag ), 0); //dont reload!
423 $book->alias('magazine')->noLoad()->sharedTag; //dont reload!
424 asrt( count( $book->sharedTag ), 0); //dont reload!
425 $book->withCondition('')->noLoad()->ownPage; //dont reload!
426 asrt( count( $book->sharedTag ), 0); //dont reload!
427 //even in combinations
428 $book->all()->with(' LIMIT 1 ')->noLoad()->sharedTag; //dont reload!
429 asrt( count( $book->sharedTag ), 0); //dont reload!
430 $book->alias('magazine')->all()->noLoad()->sharedTag; //dont reload!
431 asrt( count( $book->sharedTag ), 0); //dont reload!
432 $book->alias('magazine')->with('LIMIT 1')->noLoad()->sharedTag; //dont reload!
433 asrt( count( $book->sharedTag ), 0); //dont reload!
434 $book->alias('magazine')->withCondition('')->noLoad()->sharedTag; //dont reload!
435 asrt( count( $book->sharedTag ), 0); //dont reload!
436 //test do not reload parent bean
437 $book->author->name = 'me';
438 asrt( $book->author->name, 'me' );
439 $book->fetchAs('author')->coauthor;
440 asrt( $book->author->name, 'me' );
441 $book->fetchAs('author')->author;
442 asrt( $book->author->name, 'me' );
443 $book->with(' LIMIT 1 ')->author;
444 asrt( $book->author->name, 'me' );
445 $book->withCondition('')->author;
446 asrt( $book->author->name, 'me' );
447 $book->all()->author;
448 asrt( $book->author->name, 'me' );
449 $book->noLoad()->author;
450 asrt( $book->author->name, 'me' );
451 $book->noLoad()->all()->author;
452 asrt( $book->author->name, 'me' );
453 $book->with('LIMIT 1')->noLoad()->all()->author;
454 asrt( $book->author->name, 'me' );
456 unset( $book->author );
457 asrt( $book->author->name, NULL );
458 $book->author->name = 'me';
459 asrt( $book->author->name, 'me' );
463 * Tests whether modifiers are cleared after reading or
464 * writing a bean property.
468 public function testClearanceOfModFlags()
470 //test base condition, retrieving list or parent should not set flags
471 $book = R::dispense( 'book' );
472 asrt( $book->getModFlags(), '' );
473 $book->ownPage = R::dispense( 'page', 2 );
474 asrt( $book->getModFlags(), '' );
475 $book->xownPage = R::dispense( 'page', 2 );
476 asrt( $book->getModFlags(), '' );
477 $book->ownPageList = R::dispense( 'page', 2 );
478 asrt( $book->getModFlags(), '' );
479 $book->xownPageList = R::dispense( 'page', 2 );
480 asrt( $book->getModFlags(), '' );
481 $book->ownPage[] = R::dispense( 'page', 1 );
482 asrt( $book->getModFlags(), '' );
483 $book->xownPage[] = R::dispense( 'page', 1 );
484 asrt( $book->getModFlags(), '' );
485 $book->ownPageList[] = R::dispense( 'page', 1 );
486 asrt( $book->getModFlags(), '' );
487 $book->xownPageList[] = R::dispense( 'page', 1 );
488 asrt( $book->getModFlags(), '' );
489 $book->sharedPage = R::dispense( 'page', 2 );
490 asrt( $book->getModFlags(), '' );
491 $book->sharedPageList = R::dispense( 'page', 2 );
492 asrt( $book->getModFlags(), '' );
493 $book->sharedPage[] = R::dispense( 'page', 1 );
494 asrt( $book->getModFlags(), '' );
495 $book->sharedPageList[] = R::dispense( 'page', 1 );
496 asrt( $book->getModFlags(), '' );
497 $book->author = R::dispense( 'author' );
498 asrt( $book->getModFlags(), '' );
499 $book->title = 'title';
500 //Test whether appropriate flags are set and whether they are cleared after
501 //accessing a property.
502 $modifiers = array('with'=>'w', 'withCondition'=>'w', 'alias'=>'a', 'fetchAs'=>'f', 'all'=>'r', 'noLoad'=>'n');
503 $properties = array('ownPage', 'ownPageList', 'xownPage', 'xownPageList', 'sharedPage', 'sharedPageList', 'author', 'title');
504 foreach( $modifiers as $modifier => $flag ) {
505 foreach( $properties as $property ) {
506 $book = R::dispense( 'book' );
507 $book->$modifier('something');
508 $flags = $book->getModFlags();
510 asrt( $flags, $expect );
512 $flags = $book->getModFlags();
516 //now test combinations and also test whether we can
517 //clear modifiers manually using the clearModifiers() method.
518 foreach( $modifiers as $modifier => $flag ) {
519 foreach( $modifiers as $modifier2 => $flag2 ) {
520 foreach( $properties as $property ) {
521 $book = R::dispense( 'book' );
522 $book->$modifier( 'something' )->$modifier2( 'something' );
523 $flags = $book->getModFlags();
524 $expect = array($flag, $flag2);
525 $expect = array_unique( $expect );
527 $expect = implode( '', $expect );
528 asrt( $flags, $expect );
529 $book->$modifier( 'something' )->$modifier2( 'something' )->clearModifiers();
530 $flags = $book->getModFlags();
532 $book->$modifier( 'something' )->$modifier2( 'something' )->clearModifiers();
534 $flags = $book->getModFlags();
539 $book = R::dispense( 'book' );
540 $book->ownPage = R::dispense( 'page', 2 );
541 $book->sharedPage = R::dispense( 'page', 2 );
543 $book = R::dispense( 'book' );
544 $book->alias('magazine')->ownPage = R::dispense( 'page', 2 );
546 //test modifier with countOwn and countShared methods
547 foreach( $modifiers as $modifier => $flag ) {
548 $book = R::dispense( 'book' );
549 if ($modifier === 'withCondition') $book->$modifier( ' 1 ' );
550 elseif ($modifier === 'with') $book->$modifier( ' LIMIT 1 ' );
551 elseif ($modifier === 'alias') $book->$modifier('magazine');
552 else $book->$modifier('something');
553 $flags = $book->getModFlags();
555 asrt( $flags, $expect );
556 $book->countOwn('page');
557 $flags = $book->getModFlags();
559 if ($modifier === 'withCondition') $book->$modifier( ' 1 ' );
560 elseif ($modifier === 'with') $book->$modifier( ' LIMIT 1 ' );
561 elseif ($modifier === 'alias') $book->$modifier('magazine');
562 else $book->$modifier('something');
563 $flags = $book->getModFlags();
565 asrt( $flags, $expect );
566 $book->countShared('page');
567 $flags = $book->getModFlags();
569 if ($modifier === 'withCondition') $book->$modifier( ' 1 ' );
570 elseif ($modifier === 'with') $book->$modifier( ' LIMIT 1 ' );
571 elseif ($modifier === 'alias') $book->$modifier('magazine');
572 else $book->$modifier('something');
573 $flags = $book->getModFlags();
575 asrt( $flags, $expect );
576 unset( $book->author );
577 $flags = $book->getModFlags();