3 namespace RedUNIT\Base;
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;
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.
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
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.
28 class Foreignkeys extends Base implements Observer
35 private $queries = array();
38 * Test whether aliases are not used if not necessary:
39 * when using fetchAs() or R::aliases().
43 public function testAutoResolvAvoid()
45 R::setAutoResolve( TRUE );
47 $book = R::dispense( 'book' );
48 $page = R::dispense( 'page' );
51 $book = $book->fresh();
52 asrt( $book->getMeta('sys.autoresolved.cover'), NULL );
54 asrt( $book->getMeta('sys.autoresolved.cover'), 'page' );
56 $book = R::dispense( 'book' );
57 $page = R::dispense( 'page' );
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 );
65 R::aliases( array( 'cover' => 'page' ) );
66 $book = R::dispense( 'book' );
67 $page = R::dispense( 'page' );
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() );
78 R::setAutoResolve( FALSE );
79 $book = R::dispense( 'book' );
80 $page = R::dispense( 'page' );
83 $book = $book->fresh();
84 asrt( $book->getMeta('sys.autoresolved.cover'), NULL );
86 asrt( $book->getMeta('sys.autoresolved.cover'), NULL );
87 R::setAutoResolve( TRUE );
91 * Test whether unique constraints are properly created using
96 public function testUniqueInspect()
98 $writer = R::getWriter();
100 $book = R::dispense( 'book' );
101 $category = R::dispense( 'category' );
102 $book->sharedCategory[] = $category;
104 asrt( count( get_uniques_for_type('book_category') ), 1 );
105 asrt( are_cols_in_unique( 'book_category', array( 'book_id', 'category_id' ) ), TRUE );
107 $book = R::dispense( 'book' );
108 $category = R::dispense( 'category' );
109 $book->via( 'library' )->sharedCategory[] = $category;
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();
117 $book = R::dispense( 'book' );
118 $category = R::dispense( 'category' );
119 $book->sharedCategory[] = $category;
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 );
126 $book = R::dispense( 'book' );
127 $book2 = R::dispense( 'book' );
128 $book->sharedBook[] = $book2;
130 asrt( count( get_uniques_for_type('book_book') ), 1 );
131 asrt( are_cols_in_unique( 'book_book', array( 'book_id', 'book2_id' ) ), TRUE );
133 $result = R::getWriter()->addUniqueConstraint( 'nonexistant', array( 'a', 'b' ) );
134 } catch( \Exception $e ) {
137 pass(); //dont crash!
138 asrt( $result, FALSE );
142 * Tests foreign keys but checks using ProxyWriter.
146 public function testFKInspect()
148 $faultyWriter = new \FaultyWriter( R::getDatabaseAdapter() );
150 $null = \ProxyWriter::callMethod( $faultyWriter, 'getForeignKeyForTypeProperty', 'test', 'test' );
152 } catch( \Exception $e ) {
155 asrt( is_null( $null ), TRUE );
156 $writer = R::getWriter();
158 $book = R::dispense( 'book' );
159 $page = R::dispense( 'page' );
160 $book->xownPage[] = $page;
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 );
168 $book = R::dispense( 'book' );
169 $page = R::dispense( 'page' );
170 $book->ownPage[] = $page;
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 );
178 $book = R::dispense( 'book' );
179 $page = R::dispense( 'page' );
180 $book->alias('magazine')->xownPage[] = $page;
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 );
190 $book = R::dispense( 'book' );
191 $page = R::dispense( 'page' );
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 );
202 $book = R::dispense( 'book' );
203 $category = R::dispense( 'category' );
204 $book->sharedTag[] = $category;
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 );
219 public function testDependency()
221 $can = $this->createBeanInCan( FALSE );
223 asrt( R::count( 'bean' ), 1 );
228 asrt( R::count( 'bean' ), 1 );
232 * Test dependencies (variation).
236 public function testDependency2()
238 $can = $this->createBeanInCan( TRUE );
240 asrt( R::count( 'bean' ), 1 );
245 asrt( R::count( 'bean' ), 0 );
247 $can = $this->createBeanInCan( FALSE );
249 asrt( R::count( 'bean' ), 1 );
253 // Bean stays, constraint removed
254 asrt( R::count( 'bean' ), 0 );
256 //need to recreate table to get rid of constraint!
259 $can = $this->createBeanInCan( FALSE );
261 asrt( R::count( 'bean' ), 1 );
265 // Bean stays, constraint removed
266 asrt( R::count( 'bean' ), 1 );
271 * Tests dependencies (variation).
275 public function testDependency3()
279 $can = $this->createCanForBean();
281 asrt( R::count( 'bean' ), 1 );
285 asrt( R::count( 'bean' ), 1 );
289 * Tests dependencies (variation).
293 public function testDependency4()
297 $can = $this->createBeanInCan( TRUE );
303 $can = $this->createCanForBean();
305 asrt( R::count( 'bean' ), 1 );
309 asrt( R::count( 'bean' ), 0 );
311 $can = $this->createBeanInCan( TRUE );
317 $can = $this->createCanForBean();
319 asrt( R::count( 'bean' ), 1 );
323 asrt( R::count( 'bean' ), 0 );
328 * The index name argument is not unique in processEmbeddedBean etc.
332 public function testIssue171()
334 R::getDatabaseAdapter()->addEventListener( 'sql_exec', $this );
336 $account = R::dispense( 'account' );
337 $user = R::dispense( 'user' );
338 $player = R::dispense( 'player' );
340 $account->ownUser[] = $user;
342 R::store( $account );
344 asrt( strpos( implode( ',', $this->queries ), 'index_foreignkey_user_account' ) !== FALSE, TRUE );
346 $this->queries = array();
348 $account->ownPlayer[] = $player;
350 R::store( $account );
352 asrt( strpos( implode( ',', $this->queries ), 'index_foreignkey_player_accou' ) !== FALSE, TRUE );
356 * Tests whether foreign keys are created correctly for certain
361 public function testCreationOfForeignKeys()
363 $this->queries = array();
365 $account = R::dispense( 'account' );
366 $user = R::dispense( 'user' );
367 $player = R::dispense( 'player' );
369 $user->account = $account;
373 asrt( strpos( implode( ',', $this->queries ), 'index_foreignkey_user_account' ) !== FALSE, TRUE );
375 $this->queries = array();
377 $player->account = $account;
381 asrt( strpos( implode( ',', $this->queries ), 'index_foreignkey_player_accou' ) !== FALSE, TRUE );
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.
389 * @return OODBBean $can
391 private function createBeanInCan( $isExcl )
393 $can = R::dispense( 'can' );
394 $bean = R::dispense( 'bean' );
396 $can->name = 'bakedbeans';
397 $bean->taste = 'salty';
400 $can->xownBean[] = $bean;
402 $can->ownBean[] = $bean;
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.
415 * @return OODBBean $can
417 private function createCanForBean()
419 $can = R::dispense( 'can' );
420 $bean = R::dispense( 'bean' );
432 * @param string $event
433 * @param Adapter $info
435 public function onEvent( $event, $info )
437 $this->queries[] = $info->getSQL();