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 aliasing functionality, i.e. fetching beans as,
14 * inferring correct type and retrieving lists as alias.
16 * @file RedUNIT/Base/Aliasing.php
17 * @desc Tests for nested beans with aliases, i.e. teacher alias for person etc.
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 Aliasing extends Base
28 * Tests automatic resolvement of parent beans
29 * without fetchAs() using inferFetchType (foreign keys).
33 public function testAutoResolver()
36 list( $project, $teacher, $student ) = R::dispenseAll( 'project,person,person' );
37 $teacher->name = 'teacher';
38 $student->name = 'student';
39 $project->teacher = $teacher;
40 $project->student = $student;
42 $project = $project->fresh();
43 asrt( ( $project->teacher instanceof OODBBean), TRUE );
44 asrt( ( $project->student instanceof OODBBean), TRUE );
45 asrt( $project->teacher->name, 'teacher' );
46 asrt( $project->student->name, 'student' );
47 $project2 = R::dispense( 'project' );
48 $teacher2 = R::dispense( 'person' );
49 $teacher2->name = 'teacher2';
50 $project2->teacher = $teacher2;
51 R::store( $project2 );
52 $project2 = $project2->fresh();
53 asrt( ( $project2->teacher instanceof OODBBean), TRUE );
54 asrt( $project2->teacher->name, 'teacher2' );
55 asrt( is_null( $project2->student ), TRUE );
56 $project = $project->fresh();
57 asrt( ( $project->fetchAs('person')->teacher instanceof OODBBean), TRUE );
58 asrt( ( $project->fetchAs('person')->student instanceof OODBBean), TRUE );
59 asrt( $project->fetchAs('person')->teacher->name, 'teacher' );
60 asrt( $project->fetchAs('person')->student->name, 'student' );
61 $project = $project->fresh();
62 $export = R::exportAll( array( $project ), TRUE );
63 asrt( isset( $export[0]['teacher']['name'] ), TRUE );
64 asrt( isset( $export[0]['student']['name'] ), TRUE );
65 asrt( $export[0]['teacher']['name'], 'teacher' );
66 asrt( $export[0]['student']['name'], 'student' );
67 //Also test the default implementation...
68 $nullWriter = new \NullWriter( R::getDatabaseAdapter() );
69 asrt( is_null( $nullWriter->inferFetchType( 'test', 'test' ) ), TRUE );
70 //Realteacher should take precedence over fetchAs-teacher, name conventions first!
71 //also: ensure we do not use autoresolv for anything except when truly necessary! (performance)
72 $realTeacher = R::dispense( 'teacher' );
73 $realTeacher->name = 'real';
74 R::store( $realTeacher );
76 asrt( $realTeacher->id, $teacher->id );
77 $project = $project->fresh();
78 asrt( $project->teacher->name, 'real' );
82 * Test for aliasing issue for LTS version.
86 public function testIssueAliasingForLTSVersion() {
87 $person = R::dispense('person');
88 $pro = R::dispense('project');
89 $c = R::dispense('course');
91 $person->alias('teacher')->ownProject[] = $pro;
92 $person->alias('student')->ownCourse[] = $c;
94 asrt($c->fresh()->fetchAs('person')->student->name, 'x');
95 asrt($pro->fresh()->fetchAs('person')->teacher->name, 'x');
96 $person = $person->fresh();
97 $person->alias('teacher')->ownProject = array();
98 $person->alias('student')->ownCourse = array();
100 asrt($c->fresh()->fetchAs('person')->student, NULL);
101 asrt($pro->fresh()->fetchAs('person')->teacher, NULL);
105 * Describing how clearing state of bean works.
106 * Every method returning somthing (except getID)
107 * clears prefix-method-state (anything set by withCond,with,alias,fetchAs).
111 public function clearStateAdditionalTests()
113 list( $project1, $project2 ) = R::dispense( 'project', 2 );
114 list( $irene, $ilse ) = R::dispense('person', 2);
115 $project1->developer = $ilse;
116 $project1->designer = $irene;
117 $ilse->name = 'Ilse';
118 $irene->name = 'Irene';
119 $project2->developer = $ilse;
120 R::storeAll( array( $project1, $project2 ) );
121 $ilse = R::load( 'person', $ilse->id );
122 asrt( count( $ilse->alias( 'developer' )->ownProject ), 2);
124 asrt( count( $ilse->ownProject ), 2);
125 asrt( count( $ilse->alias( 'designer' )->ownProject ), 0);
127 asrt( count( $ilse->ownProject ), 0);
129 asrt( count( $ilse->setAttr( 'a', 'b' )->alias( 'developer' )->ownProject ), 2);
131 $ilse = $ilse->fresh();
132 //attr clears state...
133 asrt( count( $ilse->alias( 'developer' )->setAttr( 'a', 'b' )->ownProject ), 0);
134 //but getID() does not!
135 $ilse = $ilse->fresh();
136 $ilse->alias('developer');
138 asrt( count( $ilse->ownProject ), 2 );
142 * Can switch fetchAs().
143 * Also checks shadow by storing.
147 public function canSwitchParentBean()
149 list( $project1, $project2 ) = R::dispense( 'project', 2 );
150 list( $irene, $ilse ) = R::dispense('person', 2);
151 $project1->developer = $ilse;
152 $project1->designer = $irene;
153 $ilse->name = 'Ilse';
154 $irene->name = 'Irene';
155 $project2->developer = $ilse;
156 R::storeAll( array( $project1, $project2 ) );
157 $project1 = R::load( 'project', $project1->id );
158 asrt( $project1->fetchAs('person')->developer->name, 'Ilse' );
159 asrt( $project1->fetchAs('person')->designer->name, 'Irene' );
160 R::store( $project1 );
161 $project1 = R::load( 'project', $project1->id );
162 asrt( $project1->fetchAs('person')->designer->name, 'Irene' );
163 asrt( $project1->fetchAs('person')->developer->name, 'Ilse' );
164 R::store( $project1 );
165 asrt( $project1->fetchAs('person')->developer->name, 'Ilse' );
166 asrt( $project1->fetchAs('person')->designer->name, 'Irene' );
167 asrt( $project1->fetchAs('person')->developer->name, 'Ilse' );
171 * Switching aliases (->alias) should not change other list during
176 public function testShadow()
178 list( $project1, $project2 ) = R::dispense( 'project', 2 );
179 list( $irene, $ilse ) = R::dispense('person', 2);
180 $project1->developer = $ilse;
181 $project1->designer = $irene;
182 $project2->developer = $ilse;
183 R::storeAll( array( $project1, $project2 ) );
184 $ilse = R::load( 'person', $ilse->id );
185 $irene = R::load( 'person', $irene->id );
186 asrt( count( $ilse->alias('developer')->ownProject ), 2 );
187 asrt( count( $ilse->alias('designer')->ownProject ), 0 );
189 $ilse = R::load( 'person', $ilse->id );
190 $irene = R::load( 'person', $irene->id );
191 asrt( count( $ilse->alias('designer')->ownProject ), 0 );
192 asrt( count( $ilse->alias('developer')->ownProject ), 2 );
193 R::storeAll( array( $ilse, $irene) );
194 $ilse = R::load( 'person', $ilse->id );
195 $irene = R::load( 'person', $irene->id );
196 asrt( count( $ilse->alias('designer')->ownProject ), 0 );
197 asrt( count( $ilse->alias('developer')->ownProject ), 2 );
198 asrt( count( $irene->alias('designer')->ownProject), 1 );
199 asrt( count( $irene->alias('developer')->ownProject), 0 );
200 R::storeAll( array( $ilse, $irene) );
201 $ilse = R::load( 'person', $ilse->id );
202 $irene = R::load( 'person', $irene->id );
203 asrt( count( $ilse->alias('designer')->ownProject ), 0 );
204 asrt( count( $ilse->alias('developer')->ownProject ), 2 );
205 asrt( count( $irene->alias('designer')->ownProject), 1 );
206 asrt( count( $irene->alias('developer')->ownProject), 0 );
210 * Issue 291. State not cleared.
214 public function testFetchTypeConfusionIssue291()
216 list( $teacher, $student ) = R::dispense( 'person', 2 ) ;
217 $teacher->name = 'jimmy' ;
218 $student->name = 'jacko' ;
219 R::store( $teacher ) ;
220 R::store( $student ) ;
221 $client = R::dispense( 'client' ) ;
222 $client->firm = 'bean AG' ;
223 R::store( $client ) ;
224 $project = R::dispense( 'project' ) ;
225 $project->teacher = $teacher ;
226 $project->student = $student ;
227 $project->client = $client ;
228 R::store( $project ) ;
229 unset( $project->student ) ;
230 R::store( $project ) ;
231 $project = R::load( 'project', 1 ) ;
232 $teacher = $project->fetchAs( 'person' )->teacher ;
233 $student = $project->fetchAs( 'person' )->student ;
234 $client = $project->client ; // this will select from "person" instead of "client"
235 asrt( $client->firm, 'bean AG' );
239 * Test switching alias (also issue #291).
243 public function testAliasSwitch()
245 $student = R::dispense( 'person' );
246 $project = R::dispense( 'project' );
247 $project->student = $student;
248 R::store( $project );
249 $person = R::load( 'person', $student->id );
250 asrt( count( $person->alias( 'student' )->ownProject ), 1);
251 asrt( count( $person->alias( 'teacher' )->ownProject ), 0);
255 * Associating two beans, then loading the associated bean
259 public function testAssociated()
261 $person = R::dispense( 'person' );
262 $person->name = 'John';
264 $course = R::dispense( 'course' );
265 $course->name = 'Math';
268 $course->teacher = $person;
269 $id = R::store( $course );
270 $course = R::load( 'course', $id );
271 $teacher = $course->fetchAs( 'person' )->teacher;
272 asrt( $teacher->name, 'John' );
274 //Trying to load a property that has an invalid name
275 $book = R::dispense( 'book' );
276 $page = R::dispense( 'page' );
277 $book->wrongProperty = array( $page );
279 $book->wrongProperty[] = $page;
282 } catch ( RedException $e ) {
284 } catch ( \Exception $e ) {
290 * Test for quick detect change.
294 public function basic()
296 $book = R::dispense( 'book' );
298 asrt( isset( $book->prop ), FALSE ); //not a very good test
299 asrt( in_array( 'prop', array_keys( $book->export() ) ), FALSE ); //better...
301 $book = R::dispense( 'book' );
302 $page = R::dispense( 'page' );
304 $book->paper = $page;
306 $id = R::store( $book );
307 $book = R::load( 'book', $id );
309 asrt( FALSE, ( isset( $book->paper ) ) );
310 asrt( FALSE, ( isset( $book->page ) ) );
313 * The following tests try to store various things that aren't
314 * beans (which is expected) with the own* and shared* properties
315 * which only accept beans as assignments, so they're expected to fail
317 foreach ( array( 'a string', 1928, TRUE, NULL, array()) as $value ) {
319 $book->ownPage[] = $value;
321 $book->sharedPage[] = $value;
324 } catch ( RedException $e ) {
326 } catch ( \Exception $e ) {
333 * Finding $person beans that have been aliased into various roles
337 public function testAliasedFinder()
339 $message = R::dispense( 'message' );
340 $message->subject = 'Roommate agreement';
341 list( $sender, $recipient ) = R::dispense( 'person', 2 );
342 $sender->name = 'Sheldon';
343 $recipient->name = 'Leonard';
344 $message->sender = $sender;
345 $message->recipient = $recipient;
346 $id = R::store( $message );
347 $message = R::load( 'message', $id );
348 asrt( $message->fetchAs( 'person' )->sender->name, 'Sheldon' );
349 asrt( $message->fetchAs( 'person' )->recipient->name, 'Leonard' );
350 $otherRecipient = R::dispense( 'person' );
351 $otherRecipient->name = 'Penny';
352 $message->recipient = $otherRecipient;
353 R::store( $message );
354 $message = R::load( 'message', $id );
355 asrt( $message->fetchAs( 'person' )->sender->name, 'Sheldon' );
356 asrt( $message->fetchAs( 'person' )->recipient->name, 'Penny' );
360 * Test Basic Fetch AS functionality.
362 public function testBasicFetchAs()
364 $project = R::dispense( 'project' );
365 $project->name = 'Mutant Project';
366 list( $teacher, $student ) = R::dispense( 'person', 2 );
367 $teacher->name = 'Charles Xavier';
368 $project->student = $student;
369 $project->student->name = 'Wolverine';
370 $project->teacher = $teacher;
371 $id = R::store( $project );
372 $project = R::load( 'project', $id );
373 asrt( $project->fetchAs( 'person' )->teacher->name, 'Charles Xavier' );
374 asrt( $project->fetchAs( 'person' )->student->name, 'Wolverine' );
378 * Test Basic list variations.
382 public function testBasicListVariations()
384 $farm = R::dispense( 'building' );
385 $village = R::dispense( 'village' );
386 $farm->name = 'farm';
387 $village->name = 'Dusty Mountains';
388 $farm->village = $village;
389 $id = R::store( $farm );
390 $farm = R::load( 'building', $id );
391 asrt( $farm->name, 'farm' );
392 asrt( $farm->village->name, 'Dusty Mountains' );
393 $village = R::dispense( 'village' );
394 list( $mill, $tavern ) = R::dispense( 'building', 2 );
395 $mill->name = 'Mill';
396 $tavern->name = 'Tavern';
397 $village->ownBuilding = array( $mill, $tavern );
398 $id = R::store( $village );
399 $village = R::load( 'village', $id );
400 asrt( count( $village->ownBuilding ), 2 );
401 $village2 = R::dispense( 'village' );
402 $army = R::dispense( 'army' );
403 $village->sharedArmy[] = $army;
404 $village2->sharedArmy[] = $army;
405 $id1 = R::store( $village );
406 $id2 = R::store( $village2 );
407 $village1 = R::load( 'village', $id1 );
408 $village2 = R::load( 'village', $id2 );
409 asrt( count( $village1->sharedArmy ), 1 );
410 asrt( count( $village2->sharedArmy ), 1 );
411 asrt( count( $village1->ownArmy ), 0 );
412 asrt( count( $village2->ownArmy ), 0 );
416 * Tests whether aliasing plays nice with beautification.
417 * Ensure that aliased column aren't beautified
421 public function testAliasWithBeautify()
423 $points = R::dispense( 'point', 2 );
424 $line = R::dispense( 'line' );
425 $line->pointA = $points[0];
426 $line->pointB = $points[1];
428 $line2 = R::dispense( 'line' );
429 $line2->pointA = $line->fetchAs('point')->pointA;
430 $line2->pointB = R::dispense( 'point' );
433 //now we have two points per line (1-to-x)
434 //I want to know which lines cross A:
435 $a = R::load( 'point', $line->pointA->id ); //reload A
436 $lines = $a->alias( 'pointA' )->ownLine;
437 asrt( count( $lines ), 2 );