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 can easily deal with hierarchies
16 * @file RedUNIT/Base/Traverse.php
17 * @desc Tests traversal functionality
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 Traverse extends Base
29 * Very simple traverse case (one-level).
33 public function testSimplestTraversal()
36 $books = R::dispense( 'book', 10 );
38 foreach( $books as $book ) {
39 $book->title = 'Book ' . ( $i++ );
41 $books[5]->marked = TRUE;
42 $shelf = R::dispense( 'shelf' );
43 $shelf->ownBook = $books;
45 $shelf->traverse('ownBookList', function( $book ) use ( &$found ) {
46 if ( $book->marked ) $found = $book;
48 asrt( ( $found->marked == TRUE ), TRUE );
49 asrt( $found->title, 'Book 6' );
53 * Tests basic traversal.
57 public function testBasicTraversal()
60 $pageA = R::dispense( 'page' )->setAttr( 'title', 'a' );
61 $pageB = R::dispense( 'page' )->setAttr( 'title', 'b' );
62 $pageC = R::dispense( 'page' )->setAttr( 'title', 'c' );
63 $pageD = R::dispense( 'page' )->setAttr( 'title', 'd' );
64 $pageE = R::dispense( 'page' )->setAttr( 'title', 'e' );
65 $pageF = R::dispense( 'page' )->setAttr( 'title', 'f' );
66 $pageG = R::dispense( 'page' )->setAttr( 'title', 'g' );
67 $pageH = R::dispense( 'page' )->setAttr( 'title', 'h' );
68 $pageA->ownPage = array( $pageB, $pageC );
69 $pageB->ownPage = array( $pageD );
70 $pageC->ownPage = array( $pageE, $pageF );
71 $pageD->ownPage = array( $pageG );
72 $pageF->ownPage = array( $pageH );
74 $pageA = $pageA->fresh();
75 //also tests non-existant column handling by count().
76 asrt( R::count( 'page', ' price = ? ', array( '5' ) ), 0);
77 asrt( R::count( 'tag', ' title = ? ', array( 'new' ) ), 0);
78 $pageA->traverse( 'ownPageList', function( $bean ) {
82 asrt( R::count( 'page', ' price = ? ', array( '5' ) ), 7);
86 * Test traversing paths, ancestry.
90 public function testTraversePaths()
93 $pageA = R::dispense( 'page' )->setAttr( 'title', 'a' );
94 $pageB = R::dispense( 'page' )->setAttr( 'title', 'b' );
95 $pageC = R::dispense( 'page' )->setAttr( 'title', 'c' );
96 $pageD = R::dispense( 'page' )->setAttr( 'title', 'd' );
97 $pageE = R::dispense( 'page' )->setAttr( 'title', 'e' );
98 $pageF = R::dispense( 'page' )->setAttr( 'title', 'f' );
99 $pageG = R::dispense( 'page' )->setAttr( 'title', 'g' );
100 $pageH = R::dispense( 'page' )->setAttr( 'title', 'h' );
101 $pageA->ownPage = array( $pageB, $pageC );
102 $pageB->ownPage = array( $pageD );
103 $pageC->ownPage = array( $pageE, $pageF );
104 $pageD->ownPage = array( $pageG );
105 $pageF->ownPage = array( $pageH );
108 $pageF->traverse( 'page', function( $page ) use ( &$parents ) {
109 $parents[] = $page->title;
111 asrt( implode( ',', $parents ), 'c,a' );
113 $pageH->traverse( 'page', function( $page ) use ( &$parents ) {
114 $parents[] = $page->title;
116 asrt( implode( ',', $parents ), 'f,c,a' );
118 $pageG->traverse( 'page', function( $page ) use ( &$parents ) {
119 $parents[] = $page->title;
121 asrt( implode( ',', $parents ), 'd,b,a' );
123 $pageA->traverse( 'ownPageList', function( $page ) use ( &$path ) {
124 $path[] = $page->title;
126 asrt( implode( ',', $path ), 'b,d,g,c,e,f,h' );
128 $pageC->traverse( 'ownPageList', function( $page ) use ( &$path ) {
129 $path[] = $page->title;
131 asrt( implode( ',', $path ), 'e,f,h' );
133 $pageA->traverse( 'ownPageList', function( $page ) use ( &$path ) {
134 $path[] = $page->title;
136 asrt( implode( ',', $path ), 'b,d,c,e,f' );
140 * Test traversal with embedded SQL snippets.
144 public function testTraversalWithSQL()
146 $tasks = R::dispense('task', 10);
147 foreach( $tasks as $key => $task ) {
148 $task->descr = 't'.$key;
150 $tasks[0]->ownTask = array( $tasks[1], $tasks[9], $tasks[7] );
151 $tasks[1]->ownTask = array( $tasks[5] );
152 $tasks[9]->ownTask = array( $tasks[3], $tasks[8] );
153 $tasks[2]->ownTask = array( $tasks[4] );
154 $tasks[7]->ownTask = array( $tasks[6] );
155 R::storeAll( $tasks );
156 $task = R::load('task', $tasks[0]->id);
158 $task->with(' ORDER BY descr ASC ')->traverse('ownTaskList', function( $t ) use ( &$todo ) {
161 asrt( implode( ',', $todo ), 't1,t5,t7,t6,t9,t3,t8' );
162 $task = R::load( 'task', $tasks[0]->id );
164 $task->withCondition( ' ( descr = ? OR descr = ? ) ', array( 't7','t6' ) )
165 ->traverse( 'ownTaskList', function( $task ) use( &$todo ){
166 $todo[] = $task->descr;
168 asrt( implode( ',', $todo ), 't7,t6' );
172 * Test traversal with aliases.
176 public function testTraversalWithAlias()
179 $book = R::dispense( 'book' );
180 $cats = R::dispense( 'category', 3 );
181 $cats[0]->gname = 'SF';
182 $cats[1]->gname = 'Fantasy';
183 $cats[2]->gname = 'Horror';
184 $book->genre = $cats[0];
185 $book->name = 'Space Story';
186 $cats[0]->genre = $cats[1];
187 $cats[2]->genre = $cats[1];
189 $book2 = R::dispense( 'book' );
190 $book2->genre = $cats[2];
191 $book2->name = 'Ghost Story';
193 $fantasy = R::load( 'category', $cats[1]->id );
195 $book = $book->fresh();
196 $book->fetchAs( 'category' )->traverse( 'genre', function( $cat ) use ( &$cats ) {
197 $cats[] = $cat->gname;
199 asrt( implode( ',', $cats ), 'SF,Fantasy' );
201 $fantasy->alias( 'genre' )
202 ->with( ' ORDER BY gname ASC ' )
203 ->traverse( 'ownCategory', function( $cat ) use ( &$catList ) {
204 $catList[] = $cat->gname;
206 asrt( implode( ',', $catList ), 'Horror,SF' );
210 * Traverse can only work with own-lists, otherwise infinite loops.
214 public function testSharedTraversal()
216 $friend = R::dispense( 'friend' );
218 $friend->traverse( 'sharedFriend', function( $friend ){ } );
220 } catch( RedException $e ) {