Yaffs site version 1.1
[yaffs-website] / vendor / gabordemooij / redbean / testing / RedUNIT / Base / Aliasing.php
1 <?php
2
3 namespace RedUNIT\Base;
4
5 use RedUNIT\Base as Base;
6 use RedBeanPHP\Facade as R;
7 use RedBeanPHP\RedException as RedException;
8 use RedBeanPHP\OODBBean as OODBBean;
9
10 /**
11  * Aliasing
12  *
13  * Tests aliasing functionality, i.e. fetching beans as,
14  * inferring correct type and retrieving lists as alias.
15  *
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
20  *
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.
24  */
25 class Aliasing extends Base
26 {
27         /**
28          * Tests automatic resolvement of parent beans
29          * without fetchAs() using inferFetchType (foreign keys).
30          *
31          * @return void
32          */
33         public function testAutoResolver()
34         {
35                 R::nuke();
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;
41                 R::store( $project );
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 );
75                 //ID must be same
76                 asrt( $realTeacher->id, $teacher->id );
77                 $project = $project->fresh();
78                 asrt( $project->teacher->name, 'real' );
79         }
80
81         /**
82          * Test for aliasing issue for LTS version.
83          *
84          * @return void
85          */
86         public function testIssueAliasingForLTSVersion() {
87                 $person = R::dispense('person');
88                 $pro = R::dispense('project');
89                 $c = R::dispense('course');
90                 $person->name = 'x';
91                 $person->alias('teacher')->ownProject[] = $pro;
92                 $person->alias('student')->ownCourse[] = $c;
93                 R::store($person);
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();
99                 R::store($person);
100                 asrt($c->fresh()->fetchAs('person')->student, NULL);
101                 asrt($pro->fresh()->fetchAs('person')->teacher, NULL);
102         }
103
104         /**
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).
108          *
109          * @return void
110          */
111         public function clearStateAdditionalTests()
112         {
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);
123                 //cached - same list
124                 asrt( count( $ilse->ownProject ), 2);
125                 asrt( count( $ilse->alias( 'designer' )->ownProject ), 0);
126                 //cached - same list
127                 asrt( count( $ilse->ownProject ), 0);
128                 //now test state
129                 asrt( count( $ilse->setAttr( 'a', 'b' )->alias( 'developer' )->ownProject ), 2);
130                 //now test state
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');
137                 $ilse->getID();
138                 asrt( count( $ilse->ownProject ), 2 );
139         }
140
141         /**
142          * Can switch fetchAs().
143          * Also checks shadow by storing.
144          *
145          * @return void
146          */
147         public function canSwitchParentBean()
148         {
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' );
168         }
169
170         /**
171          * Switching aliases (->alias) should not change other list during
172          * storage.
173          *
174          * @return void
175          */
176         public function testShadow()
177         {
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 );
188                 R::store( $ilse );
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 );
207         }
208
209         /**
210          * Issue 291. State not cleared.
211          *
212          * @return void
213          */
214         public function testFetchTypeConfusionIssue291()
215         {
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' );
236         }
237
238         /**
239          * Test switching alias (also issue #291).
240          *
241          * @return void
242          */
243         public function testAliasSwitch()
244         {
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);
252         }
253
254         /**
255          * Associating two beans, then loading the associated bean
256          *
257          * @return void
258          */
259         public function testAssociated()
260         {
261                 $person       = R::dispense( 'person' );
262                 $person->name = 'John';
263                 R::store( $person );
264                 $course       = R::dispense( 'course' );
265                 $course->name = 'Math';
266
267                 R::store( $course );
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' );
273
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 );
278                 try {
279                         $book->wrongProperty[] = $page;
280                         R::store( $book );
281                         fail();
282                 } catch ( RedException $e ) {
283                         pass();
284                 } catch ( \Exception $e ) {
285                         fail();
286                 }
287         }
288
289         /**
290          * Test for quick detect change.
291          *
292          * @return void
293          */
294         public function basic()
295         {
296                 $book = R::dispense( 'book' );
297
298                 asrt( isset( $book->prop ), FALSE ); //not a very good test
299                 asrt( in_array( 'prop', array_keys( $book->export() ) ), FALSE ); //better...
300
301                 $book = R::dispense( 'book' );
302                 $page = R::dispense( 'page' );
303
304                 $book->paper = $page;
305
306                 $id   = R::store( $book );
307                 $book = R::load( 'book', $id );
308
309                 asrt( FALSE, ( isset( $book->paper ) ) );
310                 asrt( FALSE, ( isset( $book->page ) ) );
311
312                 /**
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
316                  */
317                 foreach ( array( 'a string', 1928, TRUE, NULL, array()) as $value ) {
318                         try {
319                                 $book->ownPage[] = $value;
320                                 R::store( $book );
321                                 $book->sharedPage[] = $value;
322                                 R::store( $book );
323                                 fail();
324                         } catch ( RedException $e ) {
325                                 pass();
326                         } catch ( \Exception $e ) {
327                                 fail();
328                         }
329                 }
330         }
331
332         /**
333          * Finding $person beans that have been aliased into various roles
334          *
335          * @return void
336          */
337         public function testAliasedFinder()
338         {
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' );
357         }
358
359         /**
360          * Test Basic Fetch AS functionality.
361          */
362         public function testBasicFetchAs()
363         {
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' );
375         }
376
377         /**
378          * Test Basic list variations.
379          *
380          * @return void
381          */
382         public function testBasicListVariations()
383         {
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 );
413         }
414
415         /**
416          * Tests whether aliasing plays nice with beautification.
417          * Ensure that aliased column aren't beautified
418          *
419          * @return void
420          */
421         public function testAliasWithBeautify()
422         {
423                 $points = R::dispense( 'point', 2 );
424                 $line   = R::dispense( 'line' );
425                 $line->pointA = $points[0];
426                 $line->pointB = $points[1];
427                 R::store( $line );
428                 $line2 = R::dispense( 'line' );
429                 $line2->pointA = $line->fetchAs('point')->pointA;
430                 $line2->pointB = R::dispense( 'point' );
431                 R::store( $line2 );
432
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 );
438         }
439 }