More tidying.
[yaffs-website] / vendor / gabordemooij / redbean / testing / RedUNIT / Base / Foreignkeys.php
1 <?php
2
3 namespace RedUNIT\Base;
4
5 use RedUNIT\Base as Base;
6 use RedBeanPHP\Facade as R;
7 use RedBeanPHP\Observer as Observer;
8 use RedBeanPHP\OODBBean as OODBBean;
9 use RedBeanPHP\Adapter as Adapter;
10 use RedBeanPHP\QueryWriter\AQueryWriter as AQueryWriter;
11
12 /**
13  * Foreignkeys
14  *
15  * Tests whether foreign keys are correctly generated and whether
16  * depending beans are correctly removed. Also tests auto resolving
17  * types inferred by inspecting foreign keys.
18  *
19  * @file    RedUNIT/Base/Foreignkeys.php
20  * @desc    Tests foreign key handling and dynamic foreign keys with
21  * @author  Gabor de Mooij and the RedBeanPHP Community
22  * @license New BSD/GPLv2
23  *
24  * (c) G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community.
25  * This source file is subject to the New BSD/GPLv2 License that is bundled
26  * with this source code in the file license.txt.
27  */
28 class Foreignkeys extends Base implements Observer
29 {
30         /**
31          * To log the queries
32          *
33          * @var array
34          */
35         private $queries = array();
36
37         /**
38          * Test whether aliases are not used if not necessary:
39          * when using fetchAs() or R::aliases().
40          *
41          * @return void
42          */
43         public function testAutoResolvAvoid()
44         {
45                 R::setAutoResolve( TRUE );
46                 R::nuke();
47                 $book = R::dispense( 'book' );
48                 $page = R::dispense( 'page' );
49                 $book->cover = $page;
50                 R::store( $book );
51                 $book = $book->fresh();
52                 asrt( $book->getMeta('sys.autoresolved.cover'), NULL );
53                 $book->cover;
54                 asrt( $book->getMeta('sys.autoresolved.cover'), 'page' );
55                 R::nuke();
56                 $book = R::dispense( 'book' );
57                 $page = R::dispense( 'page' );
58                 $book->cover = $page;
59                 R::store( $book );
60                 $book = $book->fresh();
61                 asrt( $book->getMeta('sys.autoresolved.cover'), NULL );
62                 $book->fetchAs('page')->cover;
63                 asrt( $book->getMeta('sys.autoresolved.cover'), NULL );
64                 R::nuke();
65                 R::aliases( array( 'cover' => 'page' ) );
66                 $book = R::dispense( 'book' );
67                 $page = R::dispense( 'page' );
68                 $book->cover = $page;
69                 R::store( $book );
70                 $book = $book->fresh();
71                 asrt( $book->getMeta('sys.autoresolved.cover'), NULL );
72                 $cover = $book->cover;
73                 asrt( ( $cover instanceof OODBBean ), TRUE );
74                 asrt( $cover->getMeta( 'type' ), 'page' );
75                 asrt( $book->getMeta('sys.autoresolved.cover'), NULL );
76                 R::aliases( array() );
77                 R::nuke();
78                 R::setAutoResolve( FALSE );
79                 $book = R::dispense( 'book' );
80                 $page = R::dispense( 'page' );
81                 $book->cover = $page;
82                 R::store( $book );
83                 $book = $book->fresh();
84                 asrt( $book->getMeta('sys.autoresolved.cover'), NULL );
85                 $book->cover;
86                 asrt( $book->getMeta('sys.autoresolved.cover'), NULL );
87                 R::setAutoResolve( TRUE );
88         }
89
90         /**
91          * Test whether unique constraints are properly created using
92          * reflection.
93          *
94          * @return void
95          */
96         public function testUniqueInspect()
97         {
98                 $writer = R::getWriter();
99                 R::nuke();
100                 $book = R::dispense( 'book' );
101                 $category = R::dispense( 'category' );
102                 $book->sharedCategory[] = $category;
103                 R::store( $book );
104                 asrt( count( get_uniques_for_type('book_category') ), 1 );
105                 asrt( are_cols_in_unique( 'book_category', array( 'book_id', 'category_id' ) ), TRUE );
106                 R::nuke();
107                 $book = R::dispense( 'book' );
108                 $category = R::dispense( 'category' );
109                 $book->via( 'library' )->sharedCategory[] = $category;
110                 R::store( $book );
111                 asrt( count( get_uniques_for_type('book_category') ), 0 );
112                 asrt( are_cols_in_unique( 'book_category', array( 'book_id', 'category_id' ) ), FALSE );
113                 asrt( count( get_uniques_for_type('library') ), 1 );
114                 asrt( are_cols_in_unique( 'library', array( 'book_id', 'category_id' ) ), TRUE );
115                 AQueryWriter::clearRenames();
116                 R::nuke();
117                 $book = R::dispense( 'book' );
118                 $category = R::dispense( 'category' );
119                 $book->sharedCategory[] = $category;
120                 R::store( $book );
121                 asrt( count( get_uniques_for_type('book_category') ), 1 );
122                 asrt( are_cols_in_unique( 'book_category', array( 'book_id', 'category_id' ) ), TRUE );
123                 asrt( count( get_uniques_for_type('library') ), 0 );
124                 asrt( are_cols_in_unique( 'library', array( 'book_id', 'category_id' ) ), FALSE );
125                 R::nuke();
126                 $book = R::dispense( 'book' );
127                 $book2 = R::dispense( 'book' );
128                 $book->sharedBook[] = $book2;
129                 R::store( $book );
130                 asrt( count( get_uniques_for_type('book_book') ), 1 );
131                 asrt( are_cols_in_unique( 'book_book', array( 'book_id', 'book2_id' ) ), TRUE );
132                 try {
133                         $result = R::getWriter()->addUniqueConstraint( 'nonexistant', array( 'a', 'b' ) );
134                 } catch( \Exception $e ) {
135                         print_r( $e ); exit;
136                 }
137                 pass(); //dont crash!
138                 asrt( $result, FALSE );
139         }
140
141         /**
142          * Tests foreign keys but checks using ProxyWriter.
143          *
144          * @return void
145          */
146         public function testFKInspect()
147         {
148                 $faultyWriter = new \FaultyWriter( R::getDatabaseAdapter() );
149                 try {
150                         $null = \ProxyWriter::callMethod( $faultyWriter, 'getForeignKeyForTypeProperty', 'test', 'test' );
151                         pass();
152                 } catch( \Exception $e ) {
153                         fail();
154                 }
155                 asrt( is_null( $null ), TRUE );
156                 $writer = R::getWriter();
157                 R::nuke();
158                 $book = R::dispense( 'book' );
159                 $page = R::dispense( 'page' );
160                 $book->xownPage[] = $page;
161                 R::store( $book );
162                 $keys = \ProxyWriter::callMethod( $writer, 'getForeignKeyForTypeProperty', 'page', 'book_id' );
163                 asrt( is_array( $keys ), TRUE );
164                 asrt( $keys['on_delete'], 'CASCADE' );
165                 $keys = \ProxyWriter::callMethod( $writer, 'getForeignKeyForTypeProperty', 'page', 'id' );
166                 asrt( is_null( $keys ), TRUE );
167                 R::nuke();
168                 $book = R::dispense( 'book' );
169                 $page = R::dispense( 'page' );
170                 $book->ownPage[] = $page;
171                 R::store( $book );
172                 $keys = \ProxyWriter::callMethod( $writer, 'getForeignKeyForTypeProperty', 'page', 'book_id' );
173                 asrt( is_array( $keys ), TRUE );
174                 asrt( $keys['on_delete'], 'SET NULL' );
175                 $keys = \ProxyWriter::callMethod( $writer, 'getForeignKeyForTypeProperty', 'page', 'id' );
176                 asrt( is_null( $keys ), TRUE );
177                 R::nuke();
178                 $book = R::dispense( 'book' );
179                 $page = R::dispense( 'page' );
180                 $book->alias('magazine')->xownPage[] = $page;
181                 R::store( $book );
182                 $keys = \ProxyWriter::callMethod( $writer, 'getForeignKeyForTypeProperty', 'page', 'magazine_id' );
183                 asrt( is_array( $keys ), TRUE );
184                 asrt( $keys['on_delete'], 'CASCADE' );
185                 $keys = \ProxyWriter::callMethod( $writer, 'getForeignKeyForTypeProperty', 'page', 'book_id' );
186                 asrt( is_null( $keys ), TRUE );
187                 $keys = \ProxyWriter::callMethod( $writer, 'getForeignKeyForTypeProperty', 'page', 'id' );
188                 asrt( is_null( $keys ), TRUE );
189                 R::nuke();
190                 $book = R::dispense( 'book' );
191                 $page = R::dispense( 'page' );
192                 $book->cover= $page;
193                 R::store( $book );
194                 $keys = \ProxyWriter::callMethod( $writer, 'getForeignKeyForTypeProperty', 'book', 'cover_id' );
195                 asrt( is_array( $keys ), TRUE );
196                 asrt( $keys['on_delete'], 'SET NULL' );
197                 $keys = \ProxyWriter::callMethod( $writer, 'getForeignKeyForTypeProperty', 'book', 'page_id' );
198                 asrt( is_null( $keys ), TRUE );
199                 $keys = \ProxyWriter::callMethod( $writer, 'getForeignKeyForTypeProperty', 'book', 'id' );
200                 asrt( is_null( $keys ), TRUE );
201                 R::nuke();
202                 $book = R::dispense( 'book' );
203                 $category = R::dispense( 'category' );
204                 $book->sharedTag[] = $category;
205                 R::store( $book );
206                 $keys = \ProxyWriter::callMethod( $writer, 'getForeignKeyForTypeProperty', 'book_category', 'book_id' );
207                 asrt( is_array( $keys ), TRUE );
208                 $keys = \ProxyWriter::callMethod( $writer, 'getForeignKeyForTypeProperty', 'book_category', 'category_id' );
209                 asrt( is_array( $keys ), TRUE );
210                 $keys = \ProxyWriter::callMethod( $writer, 'getForeignKeyForTypeProperty', 'book_category', 'id' );
211                 asrt( is_null( $keys ), TRUE );
212         }
213
214         /**
215          * Test dependencies.
216          *
217          * @return void
218          */
219         public function testDependency()
220         {
221                 $can = $this->createBeanInCan( FALSE );
222
223                 asrt( R::count( 'bean' ), 1 );
224
225                 R::trash( $can );
226
227                 // Bean stays
228                 asrt( R::count( 'bean' ), 1 );
229         }
230
231         /**
232          * Test dependencies (variation).
233          *
234          * @return void
235          */
236         public function testDependency2()
237         {
238                 $can = $this->createBeanInCan( TRUE );
239
240                 asrt( R::count( 'bean' ), 1 );
241
242                 R::trash( $can );
243
244                 // Bean gone
245                 asrt( R::count( 'bean' ), 0 );
246
247                 $can = $this->createBeanInCan( FALSE );
248
249                 asrt( R::count( 'bean' ), 1 );
250
251                 R::trash( $can );
252
253                 // Bean stays, constraint removed
254                 asrt( R::count( 'bean' ), 0 );
255
256                 //need to recreate table to get rid of constraint!
257                 R::nuke();
258
259                 $can = $this->createBeanInCan( FALSE );
260
261                 asrt( R::count( 'bean' ), 1 );
262
263                 R::trash( $can );
264
265                 // Bean stays, constraint removed
266                 asrt( R::count( 'bean' ), 1 );
267
268         }
269
270         /**
271          * Tests dependencies (variation).
272          *
273          * @return void
274          */
275         public function testDependency3()
276         {
277                 R::nuke();
278
279                 $can = $this->createCanForBean();
280
281                 asrt( R::count( 'bean' ), 1 );
282
283                 R::trash( $can );
284
285                 asrt( R::count( 'bean' ), 1 );
286         }
287
288         /**
289          * Tests dependencies (variation).
290          *
291          * @return void
292          */
293         public function testDependency4()
294         {
295                 R::nuke();
296
297                 $can = $this->createBeanInCan( TRUE );
298
299                 R::store( $can );
300
301                 R::trash( $can );
302
303                 $can = $this->createCanForBean();
304
305                 asrt( R::count( 'bean' ), 1 );
306
307                 R::trash( $can );
308
309                 asrt( R::count( 'bean' ), 0 );
310
311                 $can = $this->createBeanInCan( TRUE );
312
313                 R::store( $can );
314
315                 R::trash( $can );
316
317                 $can = $this->createCanForBean();
318
319                 asrt( R::count( 'bean' ), 1 );
320
321                 R::trash( $can );
322
323                 asrt( R::count( 'bean' ), 0 );
324         }
325
326         /**
327          * Issue #171
328          * The index name argument is not unique in processEmbeddedBean etc.
329          *
330          * @return void
331          */
332         public function testIssue171()
333         {
334                 R::getDatabaseAdapter()->addEventListener( 'sql_exec', $this );
335
336                 $account = R::dispense( 'account' );
337                 $user    = R::dispense( 'user' );
338                 $player  = R::dispense( 'player' );
339
340                 $account->ownUser[] = $user;
341
342                 R::store( $account );
343
344                 asrt( strpos( implode( ',', $this->queries ), 'index_foreignkey_user_account' ) !== FALSE, TRUE );
345
346                 $this->queries = array();
347
348                 $account->ownPlayer[] = $player;
349
350                 R::store( $account );
351
352                 asrt( strpos( implode( ',', $this->queries ), 'index_foreignkey_player_accou' ) !== FALSE, TRUE );
353         }
354
355         /**
356          * Tests whether foreign keys are created correctly for certain
357          * relations.
358          *
359          * @return void
360          */
361         public function testCreationOfForeignKeys()
362         {
363                 $this->queries = array();
364
365                 $account = R::dispense( 'account' );
366                 $user    = R::dispense( 'user' );
367                 $player  = R::dispense( 'player' );
368
369                 $user->account = $account;
370
371                 R::store( $user );
372
373                 asrt( strpos( implode( ',', $this->queries ), 'index_foreignkey_user_account' ) !== FALSE, TRUE );
374
375                 $this->queries = array();
376
377                 $player->account = $account;
378
379                 R::store( $player );
380
381                 asrt( strpos( implode( ',', $this->queries ), 'index_foreignkey_player_accou' ) !== FALSE, TRUE );
382         }
383
384         /**
385          * Test helper method.
386          * Creates a bean in a can. The bean will get a reference
387          * to the can and can be made dependent.
388          *
389          * @return OODBBean $can
390          */
391         private function createBeanInCan( $isExcl )
392         {
393                 $can  = R::dispense( 'can' );
394                 $bean = R::dispense( 'bean' );
395
396                 $can->name   = 'bakedbeans';
397                 $bean->taste = 'salty';
398
399                 if ($isExcl) {
400                         $can->xownBean[] = $bean;
401                 } else {
402                         $can->ownBean[] = $bean;
403                 }
404
405                 R::store( $can );
406
407                 return $can;
408         }
409
410         /**
411          * Test helper method.
412          * Creates a bean in a can beginning with the bean. The bean will get a reference
413          * to the can and can be made dependent.
414          *
415          * @return OODBBean $can
416          */
417         private function createCanForBean()
418         {
419                 $can  = R::dispense( 'can' );
420                 $bean = R::dispense( 'bean' );
421
422                 $bean->can = $can;
423
424                 R::store( $bean );
425
426                 return $can;
427         }
428
429         /**
430          * Log queries
431          *
432          * @param string          $event
433          * @param Adapter $info
434          */
435         public function onEvent( $event, $info )
436         {
437                 $this->queries[] = $info->getSQL();
438         }
439 }