PageRenderTime 61ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/Propel/Tests/Generator/Builder/Om/GeneratedObjectTest.php

http://github.com/propelorm/Propel2
PHP | 1838 lines | 1188 code | 293 blank | 357 comment | 10 complexity | f88f38a42a741446630ae036c48376af MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * MIT License. This file is part of the Propel package.
  4. * For the full copyright and license information, please view the LICENSE
  5. * file that was distributed with this source code.
  6. */
  7. namespace Propel\Tests\Generator\Builder\Om;
  8. use DateTime;
  9. use Exception;
  10. use MyNameSpace\TestKeyTypeTable;
  11. use Propel\Generator\Config\QuickGeneratorConfig;
  12. use Propel\Tests\Bookstore\BookClubList;
  13. use Propel\Generator\Util\QuickBuilder;
  14. use Propel\Runtime\ActiveQuery\Criteria;
  15. use Propel\Runtime\Adapter\Pdo\SqliteAdapter;
  16. use Propel\Runtime\Collection\ObjectCollection;
  17. use Propel\Runtime\Exception\BadMethodCallException;
  18. use Propel\Runtime\Map\TableMap;
  19. use Propel\Runtime\Propel;
  20. use Propel\Tests\Bookstore\AcctAuditLog;
  21. use Propel\Tests\Bookstore\AcctAuditLogQuery;
  22. use Propel\Tests\Bookstore\Author;
  23. use Propel\Tests\Bookstore\AuthorQuery;
  24. use Propel\Tests\Bookstore\Book;
  25. use Propel\Tests\Bookstore\BookOpinion;
  26. use Propel\Tests\Bookstore\BookOpinionQuery;
  27. use Propel\Tests\Bookstore\BookQuery;
  28. use Propel\Tests\Bookstore\BookReader;
  29. use Propel\Tests\Bookstore\Bookstore;
  30. use Propel\Tests\Bookstore\BookstoreContest;
  31. use Propel\Tests\Bookstore\BookstoreContestEntry;
  32. use Propel\Tests\Bookstore\BookstoreEmployee;
  33. use Propel\Tests\Bookstore\BookstoreEmployeeAccount;
  34. use Propel\Tests\Bookstore\BookstoreEmployeeAccountQuery;
  35. use Propel\Tests\Bookstore\BookstoreEmployeeQuery;
  36. use Propel\Tests\Bookstore\BookstoreQuery;
  37. use Propel\Tests\Bookstore\BookstoreSale;
  38. use Propel\Tests\Bookstore\BookSummary;
  39. use Propel\Tests\Bookstore\BookSummaryQuery;
  40. use Propel\Tests\Bookstore\Contest;
  41. use Propel\Tests\Bookstore\ContestQuery;
  42. use Propel\Tests\Bookstore\Country;
  43. use Propel\Tests\Bookstore\CountryQuery;
  44. use Propel\Tests\Bookstore\CountryTranslationQuery;
  45. use Propel\Tests\Bookstore\Customer;
  46. use Propel\Tests\Bookstore\CustomerQuery;
  47. use Propel\Tests\Bookstore\Map\AcctAuditLogTableMap;
  48. use Propel\Tests\Bookstore\Map\AuthorTableMap;
  49. use Propel\Tests\Bookstore\Map\BookstoreEmployeeAccountTableMap;
  50. use Propel\Tests\Bookstore\Map\BookstoreEmployeeTableMap;
  51. use Propel\Tests\Bookstore\Map\BookTableMap;
  52. use Propel\Tests\Bookstore\Map\ContestTableMap;
  53. use Propel\Tests\Bookstore\Map\CustomerTableMap;
  54. use Propel\Tests\Bookstore\Map\PublisherTableMap;
  55. use Propel\Tests\Bookstore\Map\ReviewTableMap;
  56. use Propel\Tests\Bookstore\Publisher;
  57. use Propel\Tests\Bookstore\PublisherQuery;
  58. use Propel\Tests\Bookstore\Review;
  59. use Propel\Tests\Common\BoxedString;
  60. use Propel\Tests\Helpers\Bookstore\Behavior\TestAuthor;
  61. use Propel\Tests\Helpers\Bookstore\Behavior\TestAuthorDeleteFalse;
  62. use Propel\Tests\Helpers\Bookstore\Behavior\TestAuthorSaveFalse;
  63. use Propel\Tests\Helpers\Bookstore\BookstoreTestBase;
  64. use ReflectionMethod;
  65. /**
  66. * Tests the generated Object classes.
  67. *
  68. * This test uses generated Bookstore classes to test the behavior of various
  69. * object operations. The _idea_ here is to test every possible generated method
  70. * from Object.tpl; if necessary, bookstore will be expanded to accommodate this.
  71. *
  72. * The database is reloaded before every test and flushed after every test. This
  73. * means that you can always rely on the contents of the databases being the same
  74. * for each test method in this class. See the BookstoreDataPopulator::populate()
  75. * method for the exact contents of the database.
  76. *
  77. * @author Hans Lellelid <hans@xmpl.org>
  78. *
  79. * @group database
  80. */
  81. class GeneratedObjectTest extends BookstoreTestBase
  82. {
  83. /**
  84. * Test saving an object after setting default values for it.
  85. *
  86. * @return void
  87. */
  88. public function testSaveWithDefaultValues()
  89. {
  90. // From the schema.xml, I am relying on the following:
  91. // - that 'Penguin' is the default Name for a Publisher
  92. // - that 2001-01-01 is the default ReviewDate for a Review
  93. // 1) check regular values (VARCHAR)
  94. $pub = new Publisher();
  95. $pub->setName('Penguin');
  96. $pub->save();
  97. $this->assertTrue($pub->getId() !== null, 'Expect Publisher to have been saved when default value set.');
  98. // 2) check date/time values
  99. $review = new Review();
  100. // note that this is different from how it's represented in schema, but should resolve to same unix timestamp
  101. $review->setReviewDate('2001-01-01');
  102. $this->assertTrue($review->isModified(), "Expect Review to have been marked 'modified' after default date/time value set.");
  103. }
  104. /**
  105. * Test isModified() to be false after setting default value second time
  106. *
  107. * @return void
  108. */
  109. public function testDefaultValueSetTwice()
  110. {
  111. $pub = new Publisher();
  112. $pub->setName('Penguin');
  113. $pub->save();
  114. $pubId = $pub->getId();
  115. PublisherTableMap::clearInstancePool();
  116. $pub2 = PublisherQuery::create()->findPk($pubId);
  117. $pub2->setName('Penguin');
  118. $this->assertFalse($pub2->isModified(), 'Expect Publisher to be not modified after setting default value second time.');
  119. }
  120. /**
  121. * @return void
  122. */
  123. public function testHasApplyDefaultValues()
  124. {
  125. $this->assertTrue(method_exists('\Propel\Tests\Bookstore\Publisher', 'applyDefaultValues'), 'Tables with default values should have an applyDefaultValues() method');
  126. $this->assertFalse(method_exists('\Propel\Tests\Bookstore\Book', 'applyDefaultValues'), 'Tables with no default values should not have an applyDefaultValues() method');
  127. }
  128. /**
  129. * Test default return values.
  130. *
  131. * @return void
  132. */
  133. public function testDefaultValues()
  134. {
  135. $r = new Review();
  136. $this->assertEquals('2001-01-01', $r->getReviewDate('Y-m-d'));
  137. $this->assertFalse($r->isModified(), 'expected isModified() to be false');
  138. $acct = new BookstoreEmployeeAccount();
  139. $this->assertEquals(true, $acct->getEnabled());
  140. $this->assertFalse($acct->isModified());
  141. $acct->setLogin('testuser');
  142. $acct->setPassword('testpass');
  143. $this->assertTrue($acct->isModified());
  144. }
  145. /**
  146. * Tests the use of default expressions and the reloadOnInsert and reloadOnUpdate attributes.
  147. *
  148. * @link http://propel.phpdb.org/trac/ticket/378
  149. * @link http://propel.phpdb.org/trac/ticket/555
  150. *
  151. * @return void
  152. */
  153. public function testDefaultExpressions()
  154. {
  155. if (Propel::getServiceContainer()->getAdapter(BookstoreEmployeeTableMap::DATABASE_NAME) instanceof SqliteAdapter) {
  156. $this->markTestSkipped('Cannot test default expressions with SQLite');
  157. }
  158. BookstoreEmployeeAccountTableMap::doDeleteAll();
  159. $b = new Bookstore();
  160. $b->setStoreName('Foo!');
  161. $b->save();
  162. $employee = new BookstoreEmployee();
  163. $employee->setName('Johnny Walker');
  164. $acct = new BookstoreEmployeeAccount();
  165. $acct->setBookstoreEmployee($employee);
  166. $acct->setLogin('test-login');
  167. $this->assertNull($acct->getCreated(), 'Expected created column to be NULL.');
  168. $this->assertNull($acct->getAuthenticator(), 'Expected authenticator column to be NULL.');
  169. $acct->save();
  170. $acct = BookstoreEmployeeAccountQuery::create()->findPk($acct->getEmployeeId());
  171. $this->assertNotNull($acct->getAuthenticator(), 'Expected a valid (non-NULL) authenticator column after save.');
  172. $this->assertEquals('Password', $acct->getAuthenticator(), "Expected authenticator='Password' after save.");
  173. $this->assertNotNull($acct->getCreated(), 'Expected a valid date after retrieving saved object.');
  174. $now = new DateTime('now');
  175. $this->assertEquals($now->format('Y-m-d'), $acct->getCreated('Y-m-d'));
  176. $acct->setCreated($now);
  177. $this->assertEquals($now->format('Y-m-d'), $acct->getCreated('Y-m-d'));
  178. // Unfortunately we can't really test the conjunction of reloadOnInsert and reloadOnUpdate when using just
  179. // default values. (At least not in a cross-db way.)
  180. }
  181. /**
  182. * Tests the use of default expressions and the reloadOnInsert attribute.
  183. *
  184. * @link http://propel.phpdb.org/trac/ticket/378
  185. * @link http://propel.phpdb.org/trac/ticket/555
  186. *
  187. * @return void
  188. */
  189. public function testDefaultExpressions_ReloadOnInsert()
  190. {
  191. if (Propel::getServiceContainer()->getAdapter(BookstoreEmployeeTableMap::DATABASE_NAME) instanceof SqliteAdapter) {
  192. $this->markTestSkipped('Cannot test default date expressions with SQLite');
  193. }
  194. // Create a new bookstore, contest, bookstore_contest, and bookstore_contest_entry
  195. $b = new Bookstore();
  196. $b->setStoreName('Barnes & Noble');
  197. $b->save();
  198. $c = new Contest();
  199. $c->setName('Bookathon Contest');
  200. $c->save();
  201. $bc = new BookstoreContest();
  202. $bc->setBookstore($b);
  203. $bc->setContest($c);
  204. $bc->save();
  205. $c = new Customer();
  206. $c->setName('Happy Customer');
  207. $c->save();
  208. $bce = new BookstoreContestEntry();
  209. $bce->setBookstore($b);
  210. $bce->setBookstoreContest($bc);
  211. $bce->setCustomer($c);
  212. $bce->save();
  213. $this->assertNotNull($bce->getEntryDate(), 'Expected a non-null entry_date after save.');
  214. }
  215. /**
  216. * Tests the overriding reloadOnInsert at runtime.
  217. *
  218. * @link http://propel.phpdb.org/trac/ticket/378
  219. * @link http://propel.phpdb.org/trac/ticket/555
  220. *
  221. * @return void
  222. */
  223. public function testDefaultExpressions_ReloadOnInsert_Override()
  224. {
  225. if (Propel::getServiceContainer()->getAdapter(BookstoreEmployeeTableMap::DATABASE_NAME) instanceof SqliteAdapter) {
  226. $this->markTestSkipped('Cannot test default date expressions with SQLite');
  227. }
  228. // Create a new bookstore, contest, bookstore_contest, and bookstore_contest_entry
  229. $b = new Bookstore();
  230. $b->setStoreName('Barnes & Noble');
  231. $b->save();
  232. $c = new Contest();
  233. $c->setName('Bookathon Contest');
  234. $c->save();
  235. $bc = new BookstoreContest();
  236. $bc->setBookstore($b);
  237. $bc->setContest($c);
  238. $bc->save();
  239. $c = new Customer();
  240. $c->setName('Happy Customer');
  241. $c->save();
  242. $bce = new BookstoreContestEntry();
  243. $bce->setBookstore($b);
  244. $bce->setBookstoreContest($bc);
  245. $bce->setCustomer($c);
  246. $bce->save(null, $skipReload = true);
  247. $this->assertNull($bce->getEntryDate(), 'Expected a NULL entry_date after save.');
  248. }
  249. /**
  250. * Tests the use of default expressions and the reloadOnUpdate attribute.
  251. *
  252. * @link http://propel.phpdb.org/trac/ticket/555
  253. *
  254. * @return void
  255. */
  256. public function testDefaultExpressions_ReloadOnUpdate()
  257. {
  258. $b = new Bookstore();
  259. $b->setStoreName('Foo!');
  260. $b->save();
  261. $sale = new BookstoreSale();
  262. $sale->setBookstore(BookstoreQuery::create()->findOne());
  263. $sale->setSaleName('Spring Sale');
  264. $sale->save();
  265. // Expect that default values are set, but not default expressions
  266. $this->assertNull($sale->getDiscount(), 'Expected discount to be NULL.');
  267. $sale->setSaleName('Winter Clearance');
  268. $sale->save();
  269. // Since reloadOnUpdate = true, we expect the discount to be set now.
  270. $this->assertNotNull($sale->getDiscount(), 'Expected discount to be non-NULL after save.');
  271. }
  272. /**
  273. * Tests the overriding reloadOnUpdate at runtime.
  274. *
  275. * @link http://propel.phpdb.org/trac/ticket/378
  276. * @link http://propel.phpdb.org/trac/ticket/555
  277. *
  278. * @return void
  279. */
  280. public function testDefaultExpressions_ReloadOnUpdate_Override()
  281. {
  282. $b = new Bookstore();
  283. $b->setStoreName('Foo!');
  284. $b->save();
  285. $sale = new BookstoreSale();
  286. $sale->setBookstore(BookstoreQuery::create()->findOne());
  287. $sale->setSaleName('Spring Sale');
  288. $sale->save();
  289. // Expect that default values are set, but not default expressions
  290. $this->assertNull($sale->getDiscount(), 'Expected discount to be NULL.');
  291. $sale->setSaleName('Winter Clearance');
  292. $sale->save(null, $skipReload = true);
  293. // Since reloadOnUpdate = true, we expect the discount to be set now.
  294. $this->assertNull($sale->getDiscount(), 'Expected NULL value for discount after save.');
  295. }
  296. /**
  297. * Testing creating & saving new object & instance pool.
  298. *
  299. * @return void
  300. */
  301. public function testObjectInstances_New()
  302. {
  303. $emp = new BookstoreEmployee();
  304. $emp->setName(md5(microtime()));
  305. $emp->save();
  306. $id = $emp->getId();
  307. $retrieved = BookstoreEmployeeQuery::create()->findPk($id);
  308. $this->assertSame($emp, $retrieved, 'Expected same object (from instance pool)');
  309. }
  310. /**
  311. * @return void
  312. */
  313. public function testObjectInstances_Fkeys()
  314. {
  315. // Establish a relationship between one employee and account
  316. // and then change the employee_id and ensure that the account
  317. // is not pulling the old employee.
  318. $pub1 = new Publisher();
  319. $pub1->setName('Publisher 1');
  320. $pub1->save();
  321. $pub2 = new Publisher();
  322. $pub2->setName('Publisher 2');
  323. $pub2->save();
  324. $book = new Book();
  325. $book->setTitle('Book Title');
  326. $book->setISBN('1234');
  327. $book->setPublisher($pub1);
  328. $book->save();
  329. $this->assertSame($pub1, $book->getPublisher());
  330. // now change values behind the scenes
  331. $con = Propel::getServiceContainer()->getConnection(BookstoreEmployeeAccountTableMap::DATABASE_NAME);
  332. $con->exec('UPDATE ' . BookTableMap::TABLE_NAME . ' SET '
  333. . ' publisher_id = ' . $pub2->getId()
  334. . ' WHERE id = ' . $book->getId());
  335. $book2 = BookQuery::create()->findPk($book->getId());
  336. $this->assertSame($book, $book2, 'Expected same book object instance');
  337. $this->assertEquals($pub1->getId(), $book->getPublisherId(), 'Expected book to have OLD publisher id before reload()');
  338. $book->reload();
  339. $this->assertEquals($pub2->getId(), $book->getPublisherId(), 'Expected book to have new publisher id');
  340. $this->assertSame($pub2, $book->getPublisher(), 'Expected book to have new publisher object associated.');
  341. // Now let's set it back, just to be double sure ...
  342. $con->exec('UPDATE ' . BookTableMap::TABLE_NAME . ' SET '
  343. . ' publisher_id = ' . $pub1->getId()
  344. . ' WHERE id = ' . $book->getId());
  345. $book->reload();
  346. $this->assertEquals($pub1->getId(), $book->getPublisherId(), 'Expected book to have old publisher id (again).');
  347. $this->assertSame($pub1, $book->getPublisher(), 'Expected book to have old publisher object associated (again).');
  348. }
  349. /**
  350. * Test the effect of typecast on primary key values and instance pool retrieval.
  351. *
  352. * @return void
  353. */
  354. public function testObjectInstancePoolTypecasting()
  355. {
  356. $reader = new BookReader();
  357. $reader->setName('Tester');
  358. $reader->save();
  359. $readerId = $reader->getId();
  360. $book = new Book();
  361. $book->setTitle('BookTest');
  362. $book->setISBN('TEST');
  363. $book->save();
  364. $bookId = $book->getId();
  365. $opinion = new BookOpinion();
  366. $opinion->setBookId((string)$bookId);
  367. $opinion->setReaderId((string)$readerId);
  368. $opinion->setRating(5);
  369. $opinion->setRecommendToFriend(false);
  370. $opinion->save();
  371. $opinion2 = BookOpinionQuery::create()->findPk([$bookId, $readerId]);
  372. $this->assertSame($opinion, $opinion2, 'Expected same object to be retrieved from differently type-casted primary key values.');
  373. }
  374. /**
  375. * Test saving an object and getting correct number of affected rows from save().
  376. * This includes tests of cascading saves to fk-related objects.
  377. *
  378. * @return void
  379. */
  380. public function testSaveReturnValues()
  381. {
  382. $author = new Author();
  383. $author->setFirstName('Mark');
  384. $author->setLastName('Kurlansky');
  385. // do not save
  386. $pub = new Publisher();
  387. $pub->setName('Penguin Books');
  388. // do not save
  389. $book = new Book();
  390. $book->setTitle('Salt: A World History');
  391. $book->setISBN('0142001619');
  392. $book->setAuthor($author);
  393. $book->setPublisher($pub);
  394. $affected = $book->save();
  395. $this->assertEquals(3, $affected, 'Expected 3 affected rows when saving book + publisher + author.');
  396. // change nothing ...
  397. $affected = $book->save();
  398. $this->assertEquals(0, $affected, 'Expected 0 affected rows when saving already-saved book.');
  399. // modify the book (UPDATE)
  400. $book->setTitle('Salt A World History');
  401. $affected = $book->save();
  402. $this->assertEquals(1, $affected, 'Expected 1 affected row when saving modified book.');
  403. // modify the related author
  404. $author->setLastName('Kurlanski');
  405. $affected = $book->save();
  406. $this->assertEquals(1, $affected, 'Expected 1 affected row when saving book with updated author.');
  407. // modify both the related author and the book
  408. $author->setLastName('Kurlansky');
  409. $book->setTitle('Salt: A World History');
  410. $affected = $book->save();
  411. $this->assertEquals(2, $affected, 'Expected 2 affected rows when saving updated book with updated author.');
  412. }
  413. /**
  414. * @return void
  415. */
  416. public function testSaveCanInsertNonEmptyObjects()
  417. {
  418. $b = new Book();
  419. $b->setTitle('foo');
  420. $b->setISBN('FA404');
  421. $b->save();
  422. $this->assertFalse($b->isNew());
  423. $this->assertNotNull($b->getId());
  424. }
  425. /**
  426. * @return void
  427. */
  428. public function testNoColsModified()
  429. {
  430. $e1 = new BookstoreEmployee();
  431. $e1->setName('Employee 1');
  432. $e2 = new BookstoreEmployee();
  433. $e2->setName('Employee 2');
  434. $super = new BookstoreEmployee();
  435. // we don't know who the supervisor is yet
  436. $super->addSubordinate($e1);
  437. $super->addSubordinate($e2);
  438. $affected = $super->save();
  439. $this->assertSame(3, $affected); // Why 3 and not 0?
  440. }
  441. /**
  442. * @return void
  443. */
  444. public function testIsModifiedIsFalseForNewObjects()
  445. {
  446. $a = new Author();
  447. $this->assertFalse($a->isModified());
  448. }
  449. /**
  450. * @return void
  451. */
  452. public function testIsModifiedIsTrueForNewObjectsWithModifications()
  453. {
  454. $a = new Author();
  455. $a->setFirstName('Foo');
  456. $this->assertTrue($a->isModified());
  457. }
  458. /**
  459. * @return void
  460. */
  461. public function testIsModifiedIsFalseForNewObjectsWithNullModifications()
  462. {
  463. $a = new Author();
  464. $a->setFirstName(null);
  465. $this->assertFalse($a->isModified());
  466. }
  467. /**
  468. * @return void
  469. */
  470. public function testIsModifiedIsFalseForObjectsAfterResetModified()
  471. {
  472. $a = new Author();
  473. $a->setFirstName('Foo');
  474. $a->resetModified();
  475. $this->assertFalse($a->isModified());
  476. }
  477. /**
  478. * @return void
  479. */
  480. public function testIsModifiedIsFalseForSavedObjects()
  481. {
  482. $a = new Author();
  483. $a->setFirstName('Foo');
  484. $a->setLastName('Bar');
  485. $a->save();
  486. $this->assertFalse($a->isModified());
  487. }
  488. /**
  489. * @return void
  490. */
  491. public function testIsModifiedIsTrueForSavedObjectsWithModifications()
  492. {
  493. $a = new Author();
  494. $a->setFirstName('Foo');
  495. $a->setLastName('Bar');
  496. $a->save();
  497. $a->setFirstName('Chuck');
  498. $a->setLastName('Norris');
  499. $this->assertTrue($a->isModified());
  500. }
  501. /**
  502. * @return void
  503. */
  504. public function testIsModifiedIsFalseAfterSetToDefaultValueOnNewObject()
  505. {
  506. $p = new Publisher();
  507. $p->setName('Penguin'); // default column value
  508. $this->assertFalse($p->isModified());
  509. }
  510. /**
  511. * @return void
  512. */
  513. public function testIsModifiedIsTrueAfterModifyingOnNonDefaultValueOnNewObject()
  514. {
  515. $p = new Publisher();
  516. $p->setName('Puffin Books');
  517. $this->assertTrue($p->isModified());
  518. }
  519. /**
  520. * @return void
  521. */
  522. public function testIsModifiedIsTrueAfterSetToDefaultValueOnModifiedObject()
  523. {
  524. $p = new Publisher();
  525. $p->setName('Puffin Books');
  526. $p->resetModified();
  527. $p->setName('Penguin'); // default column value
  528. $this->assertTrue($p->isModified());
  529. }
  530. /**
  531. * @return void
  532. */
  533. public function testIsModifiedIsFalseAfterChangingColumnTypeButNotValue()
  534. {
  535. $a = new Author();
  536. $a->setFirstName('1');
  537. $a->setAge(25);
  538. $a->resetModified();
  539. $a->setAge('25');
  540. $this->assertFalse($a->isModified());
  541. $a->setFirstName(1);
  542. $this->assertFalse($a->isModified());
  543. }
  544. /**
  545. * @return void
  546. */
  547. public function testIsModifiedAndNullValues()
  548. {
  549. $a = new Author();
  550. $a->setFirstName('');
  551. $a->setLastName('Bar');
  552. $a->setAge(0);
  553. $a->save();
  554. $a->setFirstName(null);
  555. $this->assertTrue($a->isModified(), 'Expected Author to be modified after changing empty string column value to NULL.');
  556. $a->setAge(null);
  557. $this->assertTrue($a->isModified(), 'Expected Author to be modified after changing 0-value int column to NULL.');
  558. $a->setFirstName('');
  559. $this->assertTrue($a->isModified(), 'Expected Author to be modified after changing NULL column value to empty string.');
  560. $a->setAge(0);
  561. $this->assertTrue($a->isModified(), 'Expected Author to be modified after changing NULL column to 0-value int.');
  562. }
  563. /**
  564. * Test checking for non-default values.
  565. *
  566. * @see http://propel.phpdb.org/trac/ticket/331
  567. *
  568. * @return void
  569. */
  570. public function testHasOnlyDefaultValues()
  571. {
  572. $emp = new BookstoreEmployee();
  573. $emp->setName(md5(microtime()));
  574. $acct2 = new BookstoreEmployeeAccount();
  575. $acct = new BookstoreEmployeeAccount();
  576. $acct->setBookstoreEmployee($emp);
  577. $acct->setLogin('foo');
  578. $acct->setPassword('bar');
  579. $acct->save();
  580. $this->assertFalse($acct->isModified(), 'Expected BookstoreEmployeeAccount NOT to be modified after save().');
  581. $acct->setEnabled(true);
  582. $acct->setPassword($acct2->getPassword());
  583. $this->assertTrue($acct->isModified(), 'Expected BookstoreEmployeeAccount to be modified after setting default values.');
  584. $this->assertTrue($acct->hasOnlyDefaultValues(), 'Expected BookstoreEmployeeAccount to not have only default values.');
  585. $acct->setPassword('bar');
  586. $this->assertFalse($acct->hasOnlyDefaultValues(), 'Expected BookstoreEmployeeAccount to have at one non-default value after setting one value to non-default.');
  587. // Test a default date/time value
  588. $r = new Review();
  589. $r->setReviewDate(new DateTime('now'));
  590. $this->assertFalse($r->hasOnlyDefaultValues());
  591. }
  592. /**
  593. * @return void
  594. */
  595. public function testHasOnlyDefaultValuesObjectType()
  596. {
  597. $databaseXml = <<<XML
  598. <database namespace="ExampleNamespace" package="Things">
  599. <table name="thing">
  600. <column name="id" type="integer"/>
  601. <column
  602. name="boxedstring"
  603. type="VARCHAR"
  604. phpType="\Propel\Tests\Common\BoxedString"
  605. default="asdf"
  606. required="true"
  607. />
  608. </table>
  609. </database>
  610. XML;
  611. $builder = new QuickBuilder();
  612. $builder->setSchema($databaseXml);
  613. $builder->build();
  614. $t = new \ExampleNamespace\Thing();
  615. $this->assertEquals(new BoxedString('asdf'), $t->getBoxedstring());
  616. $this->assertTrue(
  617. $t->hasOnlyDefaultValues(),
  618. 'default boxed string should be reported as Object has only default values'
  619. );
  620. }
  621. /**
  622. * @return void
  623. */
  624. public function testCountRefFk()
  625. {
  626. $book = new Book();
  627. $book->setTitle('Test Book');
  628. $book->setISBN('TT-EE-SS-TT');
  629. $num = 5;
  630. for ($i = 2; $i < $num + 2; $i++) {
  631. $r = new Review();
  632. $r->setReviewedBy('Hans ' . $num);
  633. $dt = new DateTime('now');
  634. $dt->modify('-' . $i . ' weeks');
  635. $r->setReviewDate($dt);
  636. $r->setRecommended(($i % 2) == 0);
  637. $book->addReview($r);
  638. }
  639. $this->assertEquals($num, $book->countReviews(), "Expected countReviews to return $num");
  640. $this->assertEquals($num, count($book->getReviews()), "Expected getReviews to return $num reviews");
  641. $book->save();
  642. BookTableMap::clearInstancePool();
  643. ReviewTableMap::clearInstancePool();
  644. $book = BookQuery::create()->findPk($book->getId());
  645. $this->assertEquals($num, $book->countReviews(), "Expected countReviews() to return $num (after save)");
  646. $this->assertEquals($num, count($book->getReviews()), "Expected getReviews() to return $num (after save)");
  647. // Now set different criteria and expect different results
  648. $c = new Criteria();
  649. $c->add(ReviewTableMap::COL_RECOMMENDED, false);
  650. $this->assertEquals(floor($num / 2), $book->countReviews($c), 'Expected ' . floor($num / 2) . ' results from countReviews(recomm=false)');
  651. // Change Criteria, run again -- expect different.
  652. $c = new Criteria();
  653. $c->add(ReviewTableMap::COL_RECOMMENDED, true);
  654. $this->assertEquals(ceil($num / 2), count($book->getReviews($c)), 'Expected ' . ceil($num / 2) . ' results from getReviews(recomm=true)');
  655. $this->assertEquals($num, $book->countReviews(), "Expected countReviews to return $num with new empty Criteria");
  656. }
  657. /**
  658. * Test copying when an object has composite primary key.
  659. *
  660. * @link http://propel.phpdb.org/trac/ticket/618
  661. *
  662. * @return void
  663. */
  664. public function testCopy_CompositePK()
  665. {
  666. $br = new BookReader();
  667. $br->setName('TestReader');
  668. $br->save();
  669. $br->copy();
  670. $b = new Book();
  671. $b->setTitle('TestBook');
  672. $b->setISBN('XX-XX-XX-XX');
  673. $b->save();
  674. $op = new BookOpinion();
  675. $op->setBookReader($br);
  676. $op->setBook($b);
  677. $op->setRating(10);
  678. $op->setRecommendToFriend(true);
  679. $op->save();
  680. $br2 = $br->copy(true);
  681. $this->assertNull($br2->getId());
  682. $opinions = $br2->getBookOpinions();
  683. $this->assertEquals(1, count($opinions), 'Expected to have a related BookOpinion after copy()');
  684. // We DO expect the reader_id to be null
  685. $this->assertNull($opinions[0]->getReaderId());
  686. // but we DO NOT expect the book_id to be null
  687. $this->assertEquals($op->getBookId(), $opinions[0]->getBookId());
  688. }
  689. /**
  690. * @return void
  691. */
  692. public function testToArray()
  693. {
  694. $b = new Book();
  695. $b->setTitle('Don Juan');
  696. $arr1 = $b->toArray();
  697. $expectedKeys = [
  698. 'Id',
  699. 'Title',
  700. 'ISBN',
  701. 'Price',
  702. 'PublisherId',
  703. 'AuthorId',
  704. ];
  705. $this->assertEquals($expectedKeys, array_keys($arr1), 'toArray() returns an associative array with TableMap::TYPE_PHPNAME keys by default');
  706. $this->assertEquals('Don Juan', $arr1['Title'], 'toArray() returns an associative array representation of the object');
  707. }
  708. /**
  709. * @return void
  710. */
  711. public function testToArrayDateTimeAsString()
  712. {
  713. $date = new DateTime('2015-01-04T16:00:02Z');
  714. $review = new Review();
  715. $review->setReviewDate($date);
  716. $bookstore = new Bookstore();
  717. $bookstore->setStoreOpenTime($date);
  718. $bookClubList = new BookClubList();
  719. $bookClubList->setCreatedAt($date);
  720. $this->assertEquals('2015-01-04', $review->toArray()['ReviewDate'], 'toArray() format colums of type DATE as Y-m-d');
  721. $this->assertEquals('16:00:02.000000', $bookstore->toArray()['StoreOpenTime'], 'toArray() format toArray() colums of type TIME as H:i:s.u');
  722. $this->assertEquals('2015-01-04 16:00:02.000000', $bookClubList->toArray()['CreatedAt'], 'toArray() format toArray() colums of type TIMESTAMP as Y-m-d H:i:s.u');
  723. }
  724. /**
  725. * @return void
  726. */
  727. public function testWithColumn()
  728. {
  729. $book = BookQuery::create()->withColumn('Title', 'TitleCopy')->findOne();
  730. $bookArray = $book->toArray();
  731. $this->assertEquals($book->getTitleCopy(), $bookArray['TitleCopy']);
  732. }
  733. /**
  734. * @return void
  735. */
  736. public function testToArrayKeyType()
  737. {
  738. $b = new Book();
  739. $b->setTitle('Don Juan');
  740. $arr1 = $b->toArray(TableMap::TYPE_COLNAME);
  741. $expectedKeys = [
  742. BookTableMap::COL_ID,
  743. BookTableMap::COL_TITLE,
  744. BookTableMap::COL_ISBN,
  745. BookTableMap::COL_PRICE,
  746. BookTableMap::COL_PUBLISHER_ID,
  747. BookTableMap::COL_AUTHOR_ID,
  748. ];
  749. $this->assertEquals($expectedKeys, array_keys($arr1), 'toArray() accepts a $keyType parameter to change the result keys');
  750. $this->assertEquals('Don Juan', $arr1[BookTableMap::COL_TITLE], 'toArray() returns an associative array representation of the object');
  751. }
  752. /**
  753. * @return void
  754. */
  755. public function testToArrayKeyTypePreDefined()
  756. {
  757. $schema = <<<EOF
  758. <database name="test" namespace="MyNameSpace">
  759. <table name="test_key_type_table">
  760. <column name="id_key_type" required="true" primaryKey="true" autoIncrement="true" type="INTEGER"/>
  761. <column name="name_key_type" type="VARCHAR"/>
  762. </table>
  763. </database>
  764. EOF;
  765. $extraConf['propel']['generator']['objectModel']['defaultKeyType'] = 'camelName';
  766. $generatorConfig = new QuickGeneratorConfig($extraConf);
  767. $builder = new QuickBuilder();
  768. $builder->setSchema($schema);
  769. $builder->setConfig($generatorConfig);
  770. $builder->buildClasses();
  771. $expectedKeys = [
  772. 'idKeyType',
  773. 'nameKeyType',
  774. ];
  775. $object = new TestKeyTypeTable();
  776. $this->assertEquals($expectedKeys, array_keys($object->toArray()), 'toArray() returns an associative array with pre-defined key type in properties.');
  777. }
  778. /**
  779. * Test that setting the auto-increment primary key will result in exception.
  780. *
  781. * @return void
  782. */
  783. public function testSettingAutoIncrementPK()
  784. {
  785. // The whole test is in a transaction, but this test needs real transactions
  786. $this->con->commit();
  787. $b = new Bookstore();
  788. $b->setId(1);
  789. $b->setStoreName('Test');
  790. try {
  791. $b->save();
  792. $this->fail('Expected setting auto-increment primary key to result in Exception');
  793. } catch (Exception $x) {
  794. $this->assertInstanceOf('\Propel\Runtime\Exception\PropelException', $x);
  795. }
  796. // ... but we should silently ignore NULL values, since these are really
  797. // the same as "not set" in PHP world.
  798. $b = new Bookstore();
  799. $b->setId(null);
  800. $b->setStoreName('Test2');
  801. try {
  802. $b->save();
  803. } catch (Exception $x) {
  804. $this->fail('Expected no exception when setting auto-increment primary key to NULL');
  805. }
  806. // success ...
  807. $this->con->beginTransaction();
  808. }
  809. /**
  810. * Checks whether we are allowed to specify the primary key on a
  811. * table with allowPkInsert=true set
  812. *
  813. * saves the object, gets it from data-source again and then compares
  814. * them for equality (thus the instance pool is also checked)
  815. *
  816. * @return void
  817. */
  818. public function testAllowPkInsertOnIdMethodNativeTable()
  819. {
  820. CustomerTableMap::doDeleteAll();
  821. $cu = new Customer();
  822. $cu->setPrimaryKey(100000);
  823. $cu->save();
  824. $this->assertEquals(100000, $cu->getPrimaryKey());
  825. $cu2 = CustomerQuery::create()->findPk(100000);
  826. $this->assertSame($cu, $cu2);
  827. }
  828. /**
  829. * Checks if it is allowed to save new, empty objects with a auto increment column
  830. *
  831. * @return void
  832. */
  833. public function testAllowEmptyWithAutoIncrement()
  834. {
  835. $bookreader = new BookReader();
  836. $bookreader->save();
  837. $this->assertFalse($bookreader->isNew());
  838. }
  839. /**
  840. * Test foreign key relationships based on references to unique cols but not PK.
  841. *
  842. * @link http://propel.phpdb.org/trac/ticket/691
  843. *
  844. * @return void
  845. */
  846. public function testUniqueFkRel()
  847. {
  848. BookstoreEmployeeAccountTableMap::doDeleteAll();
  849. $employee = new BookstoreEmployee();
  850. $employee->setName('Johnny Walker');
  851. $acct = new BookstoreEmployeeAccount();
  852. $acct->setBookstoreEmployee($employee);
  853. $acct->setLogin('test-login');
  854. $acct->save();
  855. $acctId = $acct->getEmployeeId();
  856. $al = new AcctAuditLog();
  857. $al->setBookstoreEmployeeAccount($acct);
  858. $al->save();
  859. $alId = $al->getId();
  860. BookstoreEmployeeTableMap::clearInstancePool();
  861. BookstoreEmployeeAccountTableMap::clearInstancePool();
  862. AcctAuditLogTableMap::clearInstancePool();
  863. $al2 = AcctAuditLogQuery::create()->findPk($alId);
  864. /** @var \Propel\Tests\Bookstore\AcctAuditLog $al2 */
  865. $mapacct = $al2->getBookstoreEmployeeAccount();
  866. $lookupacct = BookstoreEmployeeAccountQuery::create()->findPk($acctId);
  867. $logs = $lookupacct->getAcctAuditLogs();
  868. $this->assertTrue(count($logs) == 1, 'Expected 1 audit log result.');
  869. $this->assertEquals($logs[0]->getId(), $al->getId(), 'Expected returned audit log to match created audit log.');
  870. }
  871. /**
  872. * @return void
  873. */
  874. public function testIsPrimaryKeyNull()
  875. {
  876. $b = new Book();
  877. $this->assertTrue($b->isPrimaryKeyNull());
  878. $b->setPrimaryKey(123);
  879. $this->assertFalse($b->isPrimaryKeyNull());
  880. $b->setPrimaryKey(null);
  881. $this->assertTrue($b->isPrimaryKeyNull());
  882. }
  883. /**
  884. * @return void
  885. */
  886. public function testIsPrimaryKeyNullComposite()
  887. {
  888. $b = new BookOpinion();
  889. $this->assertTrue($b->isPrimaryKeyNull());
  890. $b->setPrimaryKey([123, 456]);
  891. $this->assertFalse($b->isPrimaryKeyNull());
  892. $b->setPrimaryKey([123, null]);
  893. $this->assertFalse($b->isPrimaryKeyNull());
  894. $b->setPrimaryKey([null, 456]);
  895. $this->assertFalse($b->isPrimaryKeyNull());
  896. $b->setPrimaryKey([null, null]);
  897. $this->assertTrue($b->isPrimaryKeyNull());
  898. }
  899. /**
  900. * @return void
  901. */
  902. public function testAddToStringDefault()
  903. {
  904. $this->assertTrue(method_exists('\Propel\Tests\Bookstore\Author', '__toString'), 'addPrimaryString() adds a __toString() method even if no column has the primaryString attribute');
  905. $author = new Author();
  906. $author->setFirstName('Leo');
  907. $author->setLastName('Tolstoi');
  908. $expected = <<<EOF
  909. Id: null
  910. FirstName: Leo
  911. LastName: Tolstoi
  912. Email: null
  913. Age: null
  914. EOF;
  915. $this->assertEquals($expected, (string)$author, 'addPrimaryString() adds a __toString() method returning the YAML representation of the object where no column is defined as primaryString');
  916. }
  917. /**
  918. * @return void
  919. */
  920. public function testAddToStringPrimaryString()
  921. {
  922. $this->assertTrue(method_exists('\Propel\Tests\Bookstore\Book', '__toString'), 'addPrimaryString() adds a __toString() method if a column has the primaryString attribute');
  923. $book = new Book();
  924. $book->setTitle('foo');
  925. $this->assertEquals('foo', (string)$book, 'addPrimaryString() adds a __toString() method returning the value of the the first column where primaryString is true');
  926. }
  927. /**
  928. * @return void
  929. */
  930. public function testPreInsert()
  931. {
  932. $author = new TestAuthor();
  933. $author->setFirstName('bogus');
  934. $author->setLastName('Lastname');
  935. $author->save();
  936. $this->assertEquals('PreInsertedFirstname', $author->getFirstName());
  937. }
  938. /**
  939. * @return void
  940. */
  941. public function testPreUpdate()
  942. {
  943. $author = new TestAuthor();
  944. $author->setFirstName('bogus');
  945. $author->setLastName('Lastname');
  946. $author->save();
  947. $author->setNew(false);
  948. $author->save();
  949. $this->assertEquals('PreUpdatedFirstname', $author->getFirstName());
  950. }
  951. /**
  952. * @return void
  953. */
  954. public function testPostInsert()
  955. {
  956. $author = new TestAuthor();
  957. $author->setFirstName('bogus');
  958. $author->setLastName('Lastname');
  959. $author->save();
  960. $this->assertEquals('PostInsertedLastName', $author->getLastName());
  961. }
  962. /**
  963. * @return void
  964. */
  965. public function testPostUpdate()
  966. {
  967. $author = new TestAuthor();
  968. $author->setFirstName('bogus');
  969. $author->setLastName('Lastname');
  970. $author->save();
  971. $author->setNew(false);
  972. $author->save();
  973. $this->assertEquals('PostUpdatedLastName', $author->getLastName());
  974. }
  975. /**
  976. * @return void
  977. */
  978. public function testPreSave()
  979. {
  980. $author = new TestAuthor();
  981. $author->setFirstName('bogus');
  982. $author->setLastName('Lastname');
  983. $author->save();
  984. $this->assertEquals('pre@save.com', $author->getEmail());
  985. }
  986. /**
  987. * @return void
  988. */
  989. public function testPreSaveFalse()
  990. {
  991. $con = Propel::getServiceContainer()->getConnection(AuthorTableMap::DATABASE_NAME);
  992. $nbNestedTransactions = $con->getNestedTransactionCount();
  993. $author = new TestAuthorSaveFalse();
  994. $author->setFirstName('bogus');
  995. $author->setLastName('Lastname');
  996. $res = $author->save($con);
  997. $this->assertEquals(0, $res);
  998. $this->assertEquals('pre@save.com', $author->getEmail());
  999. $this->assertNotEquals(115, $author->getAge());
  1000. $this->assertTrue($author->isNew());
  1001. $this->assertEquals($nbNestedTransactions, $con->getNestedTransactionCount());
  1002. }
  1003. /**
  1004. * @return void
  1005. */
  1006. public function testPostSave()
  1007. {
  1008. $author = new TestAuthor();
  1009. $author->setFirstName('bogus');
  1010. $author->setLastName('Lastname');
  1011. $author->save();
  1012. $this->assertEquals(115, $author->getAge());
  1013. }
  1014. /**
  1015. * @return void
  1016. */
  1017. public function testPreDelete()
  1018. {
  1019. $author = new TestAuthor();
  1020. $author->setFirstName('bogus');
  1021. $author->setLastName('Lastname');
  1022. $author->save();
  1023. $author->delete();
  1024. $this->assertEquals('Pre-Deleted', $author->getFirstName());
  1025. }
  1026. /**
  1027. * @return void
  1028. */
  1029. public function testPreDeleteFalse()
  1030. {
  1031. $con = Propel::getServiceContainer()->getConnection(AuthorTableMap::DATABASE_NAME);
  1032. $author = new TestAuthorDeleteFalse();
  1033. $author->setFirstName('bogus');
  1034. $author->setLastName('Lastname');
  1035. $author->save($con);
  1036. $author->delete($con);
  1037. $this->assertEquals('Pre-Deleted', $author->getFirstName());
  1038. $this->assertNotEquals('Post-Deleted', $author->getLastName());
  1039. $this->assertFalse($author->isDeleted());
  1040. $this->assertEquals(1, $con->getNestedTransactionCount());
  1041. }
  1042. /**
  1043. * @return void
  1044. */
  1045. public function testPostDelete()
  1046. {
  1047. $author = new TestAuthor();
  1048. $author->setFirstName('bogus');
  1049. $author->setLastName('Lastname');
  1050. $author->save();
  1051. $author->delete();
  1052. $this->assertEquals('Post-Deleted', $author->getLastName());
  1053. }
  1054. /**
  1055. * @return void
  1056. */
  1057. public function testMagicVirtualColumnGetter()
  1058. {
  1059. $book = new Book();
  1060. $book->setVirtualColumn('Foo', 'bar');
  1061. $this->assertEquals('bar', $book->getFoo(), 'generated __call() catches getters for virtual columns');
  1062. $book = new Book();
  1063. $book->setVirtualColumn('foo', 'bar');
  1064. $this->assertEquals('bar', $book->getFoo(), 'generated __call() catches getters for virtual columns starting with a lowercase character');
  1065. }
  1066. /**
  1067. * @return void
  1068. */
  1069. public function testMagicCallUndefined()
  1070. {
  1071. $this->expectException(BadMethodCallException::class);
  1072. $book = new Book();
  1073. $book->fooMethodName();
  1074. }
  1075. public static function conditionsForTestReadOnly()
  1076. {
  1077. return [
  1078. ['reload'],
  1079. ['delete'],
  1080. ['save'],
  1081. ['doSave'],
  1082. ['importFrom'],
  1083. ];
  1084. }
  1085. public static function conditionsForTestVisibility()
  1086. {
  1087. return [
  1088. ['setCode'],
  1089. ['setCapital'],
  1090. ];
  1091. }
  1092. /**
  1093. * @dataProvider conditionsForTestVisibility
  1094. *
  1095. * @return void
  1096. */
  1097. public function testMethodVisibility($method)
  1098. {
  1099. $cv = new Country();
  1100. $reflectionMethod = new ReflectionMethod($cv, $method);
  1101. $this->assertTrue($reflectionMethod->isProtected(), 'readOnly tables end up with no callable `' . $method . '` method in the generated object class');
  1102. }
  1103. /**
  1104. * @dataProvider conditionsForTestReadOnly
  1105. *
  1106. * @return void
  1107. */
  1108. public function testReadOnly($method)
  1109. {
  1110. $cv = new Country();
  1111. $this->assertFalse(method_exists($cv, $method), 'readOnly tables end up with no ' . $method . ' method in the generated object class');
  1112. }
  1113. /**
  1114. * @return void
  1115. */
  1116. public function testReadOnlyRelations()
  1117. {
  1118. //add countries
  1119. CountryTranslationQuery::create()->deleteAll();
  1120. CountryQuery::create()->deleteAll();
  1121. $stmt = $this->con->prepare('INSERT INTO country VALUES (?, ?)');
  1122. $stmt->execute(['fr', 'Paris']);
  1123. $stmt->execute(['us', 'Washington']);
  1124. $stmt->execute(['de', 'Berlin']);
  1125. $stmt = $this->con->prepare('INSERT INTO country_translation (country_code, language_code, label) VALUES (?, ?, ?)');
  1126. $stmt->execute(['fr', 'fr_FR', 'France']);
  1127. $stmt->execute(['us', 'us_US', 'United States America']);
  1128. $stmt->execute(['de', 'de_DE', 'Berlin']);
  1129. $contest = new Contest();
  1130. $contest->setName('Symfony Live 2014');
  1131. $contest->setCountryCode('fr');
  1132. $contest->save();
  1133. ContestTableMap::clearInstancePool();
  1134. $contestDb = ContestQuery::create()
  1135. ->joinWith('Contest.Country')
  1136. ->joinWith('Country.CountryTranslation')
  1137. ->findPk($contest->getId());
  1138. $translations = $contestDb->getCountry()->getCountryTranslations();
  1139. $this->assertCount(1, $translations);
  1140. $this->assertEquals('France', $translations[0]->getLabel());
  1141. }
  1142. /**
  1143. * @return void
  1144. */
  1145. public function testSetterOneToMany()
  1146. {
  1147. // Ensure no data
  1148. BookQuery::create()->deleteAll();
  1149. AuthorQuery::create()->deleteAll();
  1150. $coll = new ObjectCollection();
  1151. $coll->setModel('\Propel\Tests\Bookstore\Book');
  1152. for ($i = 0; $i < 3; $i++) {
  1153. $b = new Book();
  1154. $b->setTitle('Title ' . $i);
  1155. $b->setISBN($i);
  1156. $coll[] = $b;
  1157. }
  1158. $this->assertEquals(3, $coll->count());
  1159. $a = new Author();
  1160. $a->setFirstName('Chuck');
  1161. $a->setLastName('Norris');
  1162. $a->setBooks($coll);
  1163. $a->save();
  1164. $this->assertInstanceOf('\Propel\Runtime\Collection\ObjectCollection', $a->getBooks());
  1165. $this->assertEquals(3, $a->getBooks()->count());
  1166. $this->assertEquals(1, AuthorQuery::create()->count());
  1167. $this->assertEquals(3, BookQuery::create()->count());
  1168. $coll->shift();
  1169. $this->assertEquals(2, $coll->count());
  1170. $a->setBooks($coll);
  1171. $a->save();
  1172. $this->assertEquals(2, $a->getBooks()->count());
  1173. $this->assertEquals(1, AuthorQuery::create()->count());
  1174. //The book is not deleted because his fk is not required
  1175. $this->assertEquals(3, BookQuery::create()->count());
  1176. $newBook = new Book();
  1177. $newBook->setTitle('My New Book');
  1178. $newBook->setIsbn(1234);
  1179. // Kind of new collection
  1180. $coll = clone $coll;
  1181. $coll[] = $newBook;
  1182. $a->setBooks($coll);
  1183. $a->save();
  1184. $this->assertEquals(3, $coll->count());
  1185. $this->assertEquals(3, $a->getBooks()->count());
  1186. $this->assertEquals(1, AuthorQuery::create()->count());
  1187. $this->assertEquals(4, BookQuery::create()->count());
  1188. // Add a new object
  1189. $newBook1 = new Book();
  1190. $newBook1->setTitle('My New Book1');
  1191. $newBook1->setIsbn(1256);
  1192. // Existing collection - The fix around reference is tested here.
  1193. $coll[] = $newBook1;
  1194. $a->setBooks($coll);
  1195. $a->save();
  1196. $this->assertEquals(4, $coll->count());
  1197. $this->assertEquals(4, $a->getBooks()->count());
  1198. $this->assertEquals(1, AuthorQuery::create()->count());
  1199. $this->assertEquals(5, BookQuery::create()->count());
  1200. // Add the same collection
  1201. $books = $a->getBooks();
  1202. $a->setBooks($books);
  1203. $a->save();
  1204. $this->assertEquals(4, $books->count());
  1205. $this->assertEquals(4, $a->getBooks()->count());
  1206. $this->assertEquals(1, AuthorQuery::create()->count());
  1207. $this->assertEquals(5, BookQuery::create()->count());
  1208. }
  1209. /**
  1210. * @return void
  1211. */
  1212. public function testSetterOneToManyWithNoData()
  1213. {
  1214. // Ensure no data
  1215. BookQuery::create()->deleteAll();
  1216. AuthorQuery::create()->deleteAll();
  1217. $books = new ObjectCollection();
  1218. $this->assertEquals(0, $books->count());
  1219. // Basic usage
  1220. $a = new Author();
  1221. $a->setFirstName('Chuck');
  1222. $a->setLastName('Norris');
  1223. $a->setBooks($books);
  1224. $a->save();
  1225. $this->assertEquals(0, $a->getBooks()->count());
  1226. $this->assertEquals(1, AuthorQuery::create()->count());
  1227. $this->assertEquals(0, BookQuery::create()->count());
  1228. }
  1229. /**
  1230. * @return void
  1231. */
  1232. public function testSetterOneToManySavesForeignObjects()
  1233. {
  1234. // Ensure no data
  1235. BookQuery::create()->deleteAll();
  1236. AuthorQuery::create()->deleteAll();
  1237. $book = new Book();
  1238. $book->setTitle('My Book');
  1239. $book->setISBN('FA404');
  1240. $book->save();
  1241. // Modify it but don't save it
  1242. $book->setTitle('My Title');
  1243. $coll = new ObjectCollection();
  1244. $coll[] = $book;
  1245. BookTableMap::clearInstancePool();
  1246. $book = BookQuery::create()->findPk($book->getPrimaryKey());
  1247. $a = new Author();
  1248. $a->setFirstName('Chuck');
  1249. $a->setLastName('Norris');
  1250. $a->setBooks($coll);
  1251. $a->save();
  1252. $this->assertEquals(1, $a->getBooks()->count());
  1253. $this->assertEquals(1, AuthorQuery::create()->count());
  1254. $this->assertEquals(1, BookQuery::create()->count());
  1255. $result = BookQuery::create()
  1256. ->filterById($book->getId())
  1257. ->select('Title')
  1258. ->findOne();
  1259. $this->assertSame('My Title', $result);
  1260. }
  1261. /**
  1262. * @return void
  1263. */
  1264. public function testSetterOneToManyWithNewObjects()
  1265. {
  1266. // Ensure no data
  1267. BookQuery::create()->deleteAll();
  1268. AuthorQuery::create()->deleteAll();
  1269. $coll = new ObjectCollection();
  1270. $coll->setModel('\Propel\Tests\Bookstore\Book');
  1271. for ($i = 0; $i < 3; $i++) {
  1272. $b = new Book();
  1273. $b->setTitle('Title ' . $i);
  1274. $b->setISBN($i);
  1275. $coll[] = $b;
  1276. }
  1277. $a = new Author();
  1278. $a->setFirstName('Chuck');
  1279. $a->setLastName('Norris');
  1280. $a->setBooks($coll);
  1281. $a->save();
  1282. $this->assertEquals(3, $coll->count());
  1283. $this->assertEquals(3, count($a->getBooks()));
  1284. $this->assertSame($coll, $a->getBooks());
  1285. $this->assertEquals(1, AuthorQuery::create()->count());
  1286. $this->assertEquals(3, BookQuery::create()->count());
  1287. }
  1288. /**
  1289. * @return void
  1290. */
  1291. public function testSetterOneToManyWithExistingObjects()
  1292. {
  1293. // Ensure no data
  1294. BookQuery::create()->deleteAll();
  1295. AuthorQuery::create()->deleteAll();
  1296. for ($i = 0; $i < 3; $i++) {
  1297. $b = new Book();
  1298. $b->setTitle('Book ' . $i);
  1299. $b->setISBN('FA404-' . $i);
  1300. $b->save();
  1301. }
  1302. BookTableMap::clearInstancePool();
  1303. $books = BookQuery::create()->find();
  1304. $a = new Author();
  1305. $a->setFirstName('Chuck');
  1306. $a->setLastName('Norris');
  1307. $a->setBooks($books);
  1308. $a->save();
  1309. $this->assertEquals(3, count($a->getBooks()));
  1310. $this->assertEquals(1, AuthorQuery::create()->count());
  1311. $this->assertEquals(3, BookQuery::create()->count());
  1312. $i = 0;
  1313. foreach ($a->getBooks() as $book) {
  1314. $this->assertEquals('Book ' . $i++, $book->getTitle());
  1315. }
  1316. }
  1317. /**
  1318. * @return void
  1319. */
  1320. public function testSetterOneToManyWithEmptyCollection()
  1321. {
  1322. // Ensure no data
  1323. BookQuery::create()->deleteAll();
  1324. AuthorQuery::create()->deleteAll();
  1325. $a = new Author();
  1326. $a->setFirstName('Chuck');
  1327. $

Large files files are truncated, but you can click here to view the full file