RelationshipTest.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. <?php
  2. include 'helpers/config.php';
  3. class NotModel {};
  4. class AuthorWithNonModelRelationship extends ActiveRecord\Model
  5. {
  6. static $pk = 'id';
  7. static $table_name = 'authors';
  8. static $has_many = array(array('books', 'class_name' => 'NotModel'));
  9. }
  10. class RelationshipTest extends DatabaseTest
  11. {
  12. protected $relationship_name;
  13. protected $relationship_names = array('has_many', 'belongs_to', 'has_one');
  14. public function set_up($connection_name=null)
  15. {
  16. parent::set_up($connection_name);
  17. Event::$belongs_to = array(array('venue'), array('host'));
  18. Venue::$has_many = array(array('events', 'order' => 'id asc'),array('hosts', 'through' => 'events', 'order' => 'hosts.id asc'));
  19. Venue::$has_one = array();
  20. Employee::$has_one = array(array('position'));
  21. Host::$has_many = array(array('events', 'order' => 'id asc'));
  22. foreach ($this->relationship_names as $name)
  23. {
  24. if (preg_match("/$name/", $this->getName(), $match))
  25. $this->relationship_name = $match[0];
  26. }
  27. }
  28. protected function get_relationship($type=null)
  29. {
  30. if (!$type)
  31. $type = $this->relationship_name;
  32. switch ($type)
  33. {
  34. case 'belongs_to';
  35. $ret = Event::find(5);
  36. break;
  37. case 'has_one';
  38. $ret = Employee::find(1);
  39. break;
  40. case 'has_many';
  41. $ret = Venue::find(2);
  42. break;
  43. }
  44. return $ret;
  45. }
  46. protected function assert_default_belongs_to($event, $association_name='venue')
  47. {
  48. $this->assert_true($event->$association_name instanceof Venue);
  49. $this->assert_equals(5,$event->id);
  50. $this->assert_equals('West Chester',$event->$association_name->city);
  51. $this->assert_equals(6,$event->$association_name->id);
  52. }
  53. protected function assert_default_has_many($venue, $association_name='events')
  54. {
  55. $this->assert_equals(2,$venue->id);
  56. $this->assert_true(count($venue->$association_name) > 1);
  57. $this->assert_equals('Yeah Yeah Yeahs',$venue->{$association_name}[0]->title);
  58. }
  59. protected function assert_default_has_one($employee, $association_name='position')
  60. {
  61. $this->assert_true($employee->$association_name instanceof Position);
  62. $this->assert_equals('physicist',$employee->$association_name->title);
  63. $this->assert_not_null($employee->id, $employee->$association_name->title);
  64. }
  65. public function test_has_many_basic()
  66. {
  67. $this->assert_default_has_many($this->get_relationship());
  68. }
  69. /**
  70. * @expectedException ActiveRecord\RelationshipException
  71. */
  72. public function test_joins_on_model_via_undeclared_association()
  73. {
  74. $x = JoinBook::first(array('joins' => array('undeclared')));
  75. }
  76. public function test_joins_only_loads_given_model_attributes()
  77. {
  78. $x = Event::first(array('joins' => array('venue')));
  79. $this->assert_sql_has('SELECT events.*',Event::table()->last_sql);
  80. $this->assert_false(array_key_exists('city', $x->attributes()));
  81. }
  82. public function test_joins_combined_with_select_loads_all_attributes()
  83. {
  84. $x = Event::first(array('select' => 'events.*, venues.city as venue_city', 'joins' => array('venue')));
  85. $this->assert_sql_has('SELECT events.*, venues.city as venue_city',Event::table()->last_sql);
  86. $this->assert_true(array_key_exists('venue_city', $x->attributes()));
  87. }
  88. public function test_belongs_to_basic()
  89. {
  90. $this->assert_default_belongs_to($this->get_relationship());
  91. }
  92. public function test_belongs_to_returns_null_when_no_record()
  93. {
  94. $event = Event::find(6);
  95. $this->assert_null($event->venue);
  96. }
  97. public function test_belongs_to_with_explicit_class_name()
  98. {
  99. Event::$belongs_to = array(array('explicit_class_name', 'class_name' => 'Venue'));
  100. $this->assert_default_belongs_to($this->get_relationship(), 'explicit_class_name');
  101. }
  102. public function test_belongs_to_with_explicit_foreign_key()
  103. {
  104. $old = Book::$belongs_to;
  105. Book::$belongs_to = array(array('explicit_author', 'class_name' => 'Author', 'foreign_key' => 'secondary_author_id'));
  106. $book = Book::find(1);
  107. $this->assert_equals(2, $book->secondary_author_id);
  108. $this->assert_equals($book->secondary_author_id, $book->explicit_author->author_id);
  109. Book::$belongs_to = $old;
  110. }
  111. public function test_belongs_to_with_select()
  112. {
  113. Event::$belongs_to[0]['select'] = 'id, city';
  114. $event = $this->get_relationship();
  115. $this->assert_default_belongs_to($event);
  116. try {
  117. $event->venue->name;
  118. $this->fail('expected Exception ActiveRecord\UndefinedPropertyException');
  119. } catch (ActiveRecord\UndefinedPropertyException $e) {
  120. $this->assert_true(strpos($e->getMessage(), 'name') !== false);
  121. }
  122. }
  123. public function test_belongs_to_with_readonly()
  124. {
  125. Event::$belongs_to[0]['readonly'] = true;
  126. $event = $this->get_relationship();
  127. $this->assert_default_belongs_to($event);
  128. try {
  129. $event->venue->save();
  130. $this->fail('expected exception ActiveRecord\ReadonlyException');
  131. } catch (ActiveRecord\ReadonlyException $e) {
  132. }
  133. $event->venue->name = 'new name';
  134. $this->assert_equals($event->venue->name, 'new name');
  135. }
  136. public function test_belongs_to_with_plural_attribute_name()
  137. {
  138. Event::$belongs_to = array(array('venues', 'class_name' => 'Venue'));
  139. $this->assert_default_belongs_to($this->get_relationship(), 'venues');
  140. }
  141. public function test_belongs_to_with_conditions_and_non_qualifying_record()
  142. {
  143. Event::$belongs_to[0]['conditions'] = "state = 'NY'";
  144. $event = $this->get_relationship();
  145. $this->assert_equals(5,$event->id);
  146. $this->assert_null($event->venue);
  147. }
  148. public function test_belongs_to_with_conditions_and_qualifying_record()
  149. {
  150. Event::$belongs_to[0]['conditions'] = "state = 'PA'";
  151. $this->assert_default_belongs_to($this->get_relationship());
  152. }
  153. public function test_belongs_to_build_association()
  154. {
  155. $event = $this->get_relationship();
  156. $values = array('city' => 'Richmond', 'state' => 'VA');
  157. $venue = $event->build_venue($values);
  158. $this->assert_equals($values, array_intersect_key($values, $venue->attributes()));
  159. }
  160. public function test_has_many_build_association()
  161. {
  162. $author = Author::first();
  163. $this->assert_equals($author->id, $author->build_books()->author_id);
  164. $this->assert_equals($author->id, $author->build_book()->author_id);
  165. }
  166. public function test_belongs_to_create_association()
  167. {
  168. $event = $this->get_relationship();
  169. $values = array('city' => 'Richmond', 'state' => 'VA', 'name' => 'Club 54', 'address' => '123 street');
  170. $venue = $event->create_venue($values);
  171. $this->assert_not_null($venue->id);
  172. }
  173. public function test_belongs_to_can_be_self_referential()
  174. {
  175. Author::$belongs_to = array(array('parent_author', 'class_name' => 'Author', 'foreign_key' => 'parent_author_id'));
  176. $author = Author::find(1);
  177. $this->assert_equals(1, $author->id);
  178. $this->assert_equals(3, $author->parent_author->id);
  179. }
  180. public function test_belongs_to_with_an_invalid_option()
  181. {
  182. Event::$belongs_to[0]['joins'] = 'venue';
  183. $event = Event::first()->venue;
  184. $this->assert_sql_doesnt_has('INNER JOIN venues ON(events.venue_id = venues.id)',Event::table()->last_sql);
  185. }
  186. public function test_has_many_with_explicit_class_name()
  187. {
  188. Venue::$has_many = array(array('explicit_class_name', 'class_name' => 'Event', 'order' => 'id asc'));;
  189. $this->assert_default_has_many($this->get_relationship(), 'explicit_class_name');
  190. }
  191. public function test_has_many_with_select()
  192. {
  193. Venue::$has_many[0]['select'] = 'title, type';
  194. $venue = $this->get_relationship();
  195. $this->assert_default_has_many($venue);
  196. try {
  197. $venue->events[0]->description;
  198. $this->fail('expected Exception ActiveRecord\UndefinedPropertyException');
  199. } catch (ActiveRecord\UndefinedPropertyException $e) {
  200. $this->assert_true(strpos($e->getMessage(), 'description') !== false);
  201. }
  202. }
  203. public function test_has_many_with_readonly()
  204. {
  205. Venue::$has_many[0]['readonly'] = true;
  206. $venue = $this->get_relationship();
  207. $this->assert_default_has_many($venue);
  208. try {
  209. $venue->events[0]->save();
  210. $this->fail('expected exception ActiveRecord\ReadonlyException');
  211. } catch (ActiveRecord\ReadonlyException $e) {
  212. }
  213. $venue->events[0]->description = 'new desc';
  214. $this->assert_equals($venue->events[0]->description, 'new desc');
  215. }
  216. public function test_has_many_with_singular_attribute_name()
  217. {
  218. Venue::$has_many = array(array('event', 'class_name' => 'Event', 'order' => 'id asc'));
  219. $this->assert_default_has_many($this->get_relationship(), 'event');
  220. }
  221. public function test_has_many_with_conditions_and_non_qualifying_record()
  222. {
  223. Venue::$has_many[0]['conditions'] = "title = 'pr0n @ railsconf'";
  224. $venue = $this->get_relationship();
  225. $this->assert_equals(2,$venue->id);
  226. $this->assert_true(empty($venue->events), is_array($venue->events));
  227. }
  228. public function test_has_many_with_conditions_and_qualifying_record()
  229. {
  230. Venue::$has_many[0]['conditions'] = "title = 'Yeah Yeah Yeahs'";
  231. $venue = $this->get_relationship();
  232. $this->assert_equals(2,$venue->id);
  233. $this->assert_equals($venue->events[0]->title,'Yeah Yeah Yeahs');
  234. }
  235. public function test_has_many_with_sql_clause_options()
  236. {
  237. Venue::$has_many[0] = array('events',
  238. 'select' => 'type',
  239. 'group' => 'type',
  240. 'limit' => 2,
  241. 'offset' => 1);
  242. Venue::first()->events;
  243. $this->assert_sql_has($this->conn->limit("SELECT type FROM events WHERE venue_id=? GROUP BY type",1,2),Event::table()->last_sql);
  244. }
  245. public function test_has_many_through()
  246. {
  247. $hosts = Venue::find(2)->hosts;
  248. $this->assert_equals(2,$hosts[0]->id);
  249. $this->assert_equals(3,$hosts[1]->id);
  250. }
  251. public function test_gh27_has_many_through_with_explicit_keys()
  252. {
  253. $property = Property::first();
  254. $this->assert_equals(1, $property->amenities[0]->amenity_id);
  255. $this->assert_equals(2, $property->amenities[1]->amenity_id);
  256. }
  257. public function test_gh16_has_many_through_inside_a_loop_should_not_cause_an_exception()
  258. {
  259. $count = 0;
  260. foreach (Venue::all() as $venue)
  261. $count += count($venue->hosts);
  262. $this->assert_true($count >= 5);
  263. }
  264. /**
  265. * @expectedException ActiveRecord\HasManyThroughAssociationException
  266. */
  267. public function test_has_many_through_no_association()
  268. {
  269. Event::$belongs_to = array(array('host'));
  270. Venue::$has_many[1] = array('hosts', 'through' => 'blahhhhhhh');
  271. $venue = $this->get_relationship();
  272. $n = $venue->hosts;
  273. $this->assert_true(count($n) > 0);
  274. }
  275. public function test_has_many_through_with_select()
  276. {
  277. Event::$belongs_to = array(array('host'));
  278. Venue::$has_many[1] = array('hosts', 'through' => 'events', 'select' => 'hosts.*, events.*');
  279. $venue = $this->get_relationship();
  280. $this->assert_true(count($venue->hosts) > 0);
  281. $this->assert_not_null($venue->hosts[0]->title);
  282. }
  283. public function test_has_many_through_with_conditions()
  284. {
  285. Event::$belongs_to = array(array('host'));
  286. Venue::$has_many[1] = array('hosts', 'through' => 'events', 'conditions' => array('events.title != ?', 'Love Overboard'));
  287. $venue = $this->get_relationship();
  288. $this->assert_true(count($venue->hosts) === 1);
  289. $this->assert_sql_has("events.title !=",ActiveRecord\Table::load('Host')->last_sql);
  290. }
  291. public function test_has_many_through_using_source()
  292. {
  293. Event::$belongs_to = array(array('host'));
  294. Venue::$has_many[1] = array('hostess', 'through' => 'events', 'source' => 'host');
  295. $venue = $this->get_relationship();
  296. $this->assert_true(count($venue->hostess) > 0);
  297. }
  298. /**
  299. * @expectedException ReflectionException
  300. */
  301. public function test_has_many_through_with_invalid_class_name()
  302. {
  303. Event::$belongs_to = array(array('host'));
  304. Venue::$has_one = array(array('invalid_assoc'));
  305. Venue::$has_many[1] = array('hosts', 'through' => 'invalid_assoc');
  306. $this->get_relationship()->hosts;
  307. }
  308. public function test_has_many_with_joins()
  309. {
  310. $x = Venue::first(array('joins' => array('events')));
  311. $this->assert_sql_has('INNER JOIN events ON(venues.id = events.venue_id)',Venue::table()->last_sql);
  312. }
  313. public function test_has_many_with_explicit_keys()
  314. {
  315. $old = Author::$has_many;
  316. Author::$has_many = array(array('explicit_books', 'class_name' => 'Book', 'primary_key' => 'parent_author_id', 'foreign_key' => 'secondary_author_id'));
  317. $author = Author::find(4);
  318. foreach ($author->explicit_books as $book)
  319. $this->assert_equals($book->secondary_author_id, $author->parent_author_id);
  320. $this->assert_true(strpos(ActiveRecord\Table::load('Book')->last_sql, "secondary_author_id") !== false);
  321. Author::$has_many = $old;
  322. }
  323. public function test_has_one_basic()
  324. {
  325. $this->assert_default_has_one($this->get_relationship());
  326. }
  327. public function test_has_one_with_explicit_class_name()
  328. {
  329. Employee::$has_one = array(array('explicit_class_name', 'class_name' => 'Position'));
  330. $this->assert_default_has_one($this->get_relationship(), 'explicit_class_name');
  331. }
  332. public function test_has_one_with_select()
  333. {
  334. Employee::$has_one[0]['select'] = 'title';
  335. $employee = $this->get_relationship();
  336. $this->assert_default_has_one($employee);
  337. try {
  338. $employee->position->active;
  339. $this->fail('expected Exception ActiveRecord\UndefinedPropertyException');
  340. } catch (ActiveRecord\UndefinedPropertyException $e) {
  341. $this->assert_true(strpos($e->getMessage(), 'active') !== false);
  342. }
  343. }
  344. public function test_has_one_with_order()
  345. {
  346. Employee::$has_one[0]['order'] = 'title';
  347. $employee = $this->get_relationship();
  348. $this->assert_default_has_one($employee);
  349. $this->assert_sql_has('ORDER BY title',Position::table()->last_sql);
  350. }
  351. public function test_has_one_with_conditions_and_non_qualifying_record()
  352. {
  353. Employee::$has_one[0]['conditions'] = "title = 'programmer'";
  354. $employee = $this->get_relationship();
  355. $this->assert_equals(1,$employee->id);
  356. $this->assert_null($employee->position);
  357. }
  358. public function test_has_one_with_conditions_and_qualifying_record()
  359. {
  360. Employee::$has_one[0]['conditions'] = "title = 'physicist'";
  361. $this->assert_default_has_one($this->get_relationship());
  362. }
  363. public function test_has_one_with_readonly()
  364. {
  365. Employee::$has_one[0]['readonly'] = true;
  366. $employee = $this->get_relationship();
  367. $this->assert_default_has_one($employee);
  368. try {
  369. $employee->position->save();
  370. $this->fail('expected exception ActiveRecord\ReadonlyException');
  371. } catch (ActiveRecord\ReadonlyException $e) {
  372. }
  373. $employee->position->title = 'new title';
  374. $this->assert_equals($employee->position->title, 'new title');
  375. }
  376. public function test_has_one_can_be_self_referential()
  377. {
  378. Author::$has_one[1] = array('parent_author', 'class_name' => 'Author', 'foreign_key' => 'parent_author_id');
  379. $author = Author::find(1);
  380. $this->assert_equals(1, $author->id);
  381. $this->assert_equals(3, $author->parent_author->id);
  382. }
  383. public function test_has_one_with_joins()
  384. {
  385. $x = Employee::first(array('joins' => array('position')));
  386. $this->assert_sql_has('INNER JOIN positions ON(employees.id = positions.employee_id)',Employee::table()->last_sql);
  387. }
  388. public function test_has_one_with_explicit_keys()
  389. {
  390. Book::$has_one = array(array('explicit_author', 'class_name' => 'Author', 'foreign_key' => 'parent_author_id', 'primary_key' => 'secondary_author_id'));
  391. $book = Book::find(1);
  392. $this->assert_equals($book->secondary_author_id, $book->explicit_author->parent_author_id);
  393. $this->assert_true(strpos(ActiveRecord\Table::load('Author')->last_sql, "parent_author_id") !== false);
  394. }
  395. public function test_dont_attempt_to_load_if_all_foreign_keys_are_null()
  396. {
  397. $event = new Event();
  398. $event->venue;
  399. $this->assert_sql_doesnt_has($this->conn->last_query,'is IS NULL');
  400. }
  401. public function test_relationship_on_table_with_underscores()
  402. {
  403. $this->assert_equals(1,Author::find(1)->awesome_person->is_awesome);
  404. }
  405. public function test_has_one_through()
  406. {
  407. Venue::$has_many = array(array('events'),array('hosts', 'through' => 'events'));
  408. $venue = Venue::first();
  409. $this->assert_true(count($venue->hosts) > 0);
  410. }
  411. /**
  412. * @expectedException ActiveRecord\RelationshipException
  413. */
  414. public function test_throw_error_if_relationship_is_not_a_model()
  415. {
  416. AuthorWithNonModelRelationship::first()->books;
  417. }
  418. public function test_gh93_and_gh100_eager_loading_respects_association_options()
  419. {
  420. Venue::$has_many = array(array('events', 'class_name' => 'Event', 'order' => 'id asc', 'conditions' => array('length(title) = ?', 14)));
  421. $venues = Venue::find(array(2, 6), array('include' => 'events'));
  422. $this->assert_sql_has("WHERE length(title) = ? AND venue_id IN(?,?) ORDER BY id asc",ActiveRecord\Table::load('Event')->last_sql);
  423. $this->assert_equals(1, count($venues[0]->events));
  424. }
  425. public function test_eager_loading_has_many_x()
  426. {
  427. $venues = Venue::find(array(2, 6), array('include' => 'events'));
  428. $this->assert_sql_has("WHERE venue_id IN(?,?)",ActiveRecord\Table::load('Event')->last_sql);
  429. foreach ($venues[0]->events as $event)
  430. $this->assert_equals($event->venue_id, $venues[0]->id);
  431. $this->assert_equals(2, count($venues[0]->events));
  432. }
  433. public function test_eager_loading_has_many_with_no_related_rows()
  434. {
  435. $venues = Venue::find(array(7, 8), array('include' => 'events'));
  436. foreach ($venues as $v)
  437. $this->assert_true(empty($v->events));
  438. $this->assert_sql_has("WHERE id IN(?,?)",ActiveRecord\Table::load('Venue')->last_sql);
  439. $this->assert_sql_has("WHERE venue_id IN(?,?)",ActiveRecord\Table::load('Event')->last_sql);
  440. }
  441. public function test_eager_loading_has_many_array_of_includes()
  442. {
  443. Author::$has_many = array(array('books'), array('awesome_people'));
  444. $authors = Author::find(array(1,2), array('include' => array('books', 'awesome_people')));
  445. $assocs = array('books', 'awesome_people');
  446. foreach ($assocs as $assoc)
  447. {
  448. $this->assert_internal_type('array', $authors[0]->$assoc);
  449. foreach ($authors[0]->$assoc as $a)
  450. $this->assert_equals($authors[0]->author_id,$a->author_id);
  451. }
  452. foreach ($assocs as $assoc)
  453. {
  454. $this->assert_internal_type('array', $authors[1]->$assoc);
  455. $this->assert_true(empty($authors[1]->$assoc));
  456. }
  457. $this->assert_sql_has("WHERE author_id IN(?,?)",ActiveRecord\Table::load('Author')->last_sql);
  458. $this->assert_sql_has("WHERE author_id IN(?,?)",ActiveRecord\Table::load('Book')->last_sql);
  459. $this->assert_sql_has("WHERE author_id IN(?,?)",ActiveRecord\Table::load('AwesomePerson')->last_sql);
  460. }
  461. public function test_eager_loading_has_many_nested()
  462. {
  463. $venues = Venue::find(array(1,2), array('include' => array('events' => array('host'))));
  464. $this->assert_equals(2, count($venues));
  465. foreach ($venues as $v)
  466. {
  467. $this->assert_true(count($v->events) > 0);
  468. foreach ($v->events as $e)
  469. {
  470. $this->assert_equals($e->host_id, $e->host->id);
  471. $this->assert_equals($v->id, $e->venue_id);
  472. }
  473. }
  474. $this->assert_sql_has("WHERE id IN(?,?)",ActiveRecord\Table::load('Venue')->last_sql);
  475. $this->assert_sql_has("WHERE venue_id IN(?,?)",ActiveRecord\Table::load('Event')->last_sql);
  476. $this->assert_sql_has("WHERE id IN(?,?,?)",ActiveRecord\Table::load('Host')->last_sql);
  477. }
  478. public function test_eager_loading_belongs_to()
  479. {
  480. $events = Event::find(array(1,2,3,5,7), array('include' => 'venue'));
  481. foreach ($events as $event)
  482. $this->assert_equals($event->venue_id, $event->venue->id);
  483. $this->assert_sql_has("WHERE id IN(?,?,?,?,?)",ActiveRecord\Table::load('Venue')->last_sql);
  484. }
  485. public function test_eager_loading_belongs_to_array_of_includes()
  486. {
  487. $events = Event::find(array(1,2,3,5,7), array('include' => array('venue', 'host')));
  488. foreach ($events as $event)
  489. {
  490. $this->assert_equals($event->venue_id, $event->venue->id);
  491. $this->assert_equals($event->host_id, $event->host->id);
  492. }
  493. $this->assert_sql_has("WHERE id IN(?,?,?,?,?)",ActiveRecord\Table::load('Event')->last_sql);
  494. $this->assert_sql_has("WHERE id IN(?,?,?,?,?)",ActiveRecord\Table::load('Host')->last_sql);
  495. $this->assert_sql_has("WHERE id IN(?,?,?,?,?)",ActiveRecord\Table::load('Venue')->last_sql);
  496. }
  497. public function test_eager_loading_belongs_to_nested()
  498. {
  499. Author::$has_many = array(array('awesome_people'));
  500. $books = Book::find(array(1,2), array('include' => array('author' => array('awesome_people'))));
  501. $assocs = array('author', 'awesome_people');
  502. foreach ($books as $book)
  503. {
  504. $this->assert_equals($book->author_id,$book->author->author_id);
  505. $this->assert_equals($book->author->author_id,$book->author->awesome_people[0]->author_id);
  506. }
  507. $this->assert_sql_has("WHERE book_id IN(?,?)",ActiveRecord\Table::load('Book')->last_sql);
  508. $this->assert_sql_has("WHERE author_id IN(?,?)",ActiveRecord\Table::load('Author')->last_sql);
  509. $this->assert_sql_has("WHERE author_id IN(?,?)",ActiveRecord\Table::load('AwesomePerson')->last_sql);
  510. }
  511. public function test_eager_loading_belongs_to_with_no_related_rows()
  512. {
  513. $e1 = Event::create(array('venue_id' => 200, 'host_id' => 200, 'title' => 'blah','type' => 'Music'));
  514. $e2 = Event::create(array('venue_id' => 200, 'host_id' => 200, 'title' => 'blah2','type' => 'Music'));
  515. $events = Event::find(array($e1->id, $e2->id), array('include' => 'venue'));
  516. foreach ($events as $e)
  517. $this->assert_null($e->venue);
  518. $this->assert_sql_has("WHERE id IN(?,?)",ActiveRecord\Table::load('Event')->last_sql);
  519. $this->assert_sql_has("WHERE id IN(?,?)",ActiveRecord\Table::load('Venue')->last_sql);
  520. }
  521. public function test_eager_loading_clones_related_objects()
  522. {
  523. $events = Event::find(array(2,3), array('include' => array('venue')));
  524. $venue = $events[0]->venue;
  525. $venue->name = "new name";
  526. $this->assert_equals($venue->id, $events[1]->venue->id);
  527. $this->assert_not_equals($venue->name, $events[1]->venue->name);
  528. $this->assert_not_equals(spl_object_hash($venue), spl_object_hash($events[1]->venue));
  529. }
  530. public function test_eager_loading_clones_nested_related_objects()
  531. {
  532. $venues = Venue::find(array(1,2,6,9), array('include' => array('events' => array('host'))));
  533. $unchanged_host = $venues[2]->events[0]->host;
  534. $changed_host = $venues[3]->events[0]->host;
  535. $changed_host->name = "changed";
  536. $this->assert_equals($changed_host->id, $unchanged_host->id);
  537. $this->assert_not_equals($changed_host->name, $unchanged_host->name);
  538. $this->assert_not_equals(spl_object_hash($changed_host), spl_object_hash($unchanged_host));
  539. }
  540. public function test_gh_23_relationships_with_joins_to_same_table_should_alias_table_name()
  541. {
  542. $old = Book::$belongs_to;
  543. Book::$belongs_to = array(
  544. array('from_', 'class_name' => 'Author', 'foreign_key' => 'author_id'),
  545. array('to', 'class_name' => 'Author', 'foreign_key' => 'secondary_author_id'),
  546. array('another', 'class_name' => 'Author', 'foreign_key' => 'secondary_author_id')
  547. );
  548. $c = ActiveRecord\Table::load('Book')->conn;
  549. $select = "books.*, authors.name as to_author_name, {$c->quote_name('from_')}.name as from_author_name, {$c->quote_name('another')}.name as another_author_name";
  550. $book = Book::find(2, array('joins' => array('to', 'from_', 'another'),
  551. 'select' => $select));
  552. $this->assert_not_null($book->from_author_name);
  553. $this->assert_not_null($book->to_author_name);
  554. $this->assert_not_null($book->another_author_name);
  555. Book::$belongs_to = $old;
  556. }
  557. public function test_gh_40_relationships_with_joins_aliases_table_name_in_conditions()
  558. {
  559. $event = Event::find(1, array('joins' => array('venue')));
  560. $this->assert_equals($event->id, $event->venue->id);
  561. }
  562. /**
  563. * @expectedException ActiveRecord\RecordNotFound
  564. */
  565. public function test_dont_attempt_eager_load_when_record_does_not_exist()
  566. {
  567. Author::find(999999, array('include' => array('books')));
  568. }
  569. };
  570. ?>