MarshallerTest.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  11. * @link http://cakephp.org CakePHP(tm) Project
  12. * @since 3.0.0
  13. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  14. */
  15. namespace Cake\Test\TestCase\ORM;
  16. use Cake\ORM\Entity;
  17. use Cake\ORM\Marshaller;
  18. use Cake\ORM\Table;
  19. use Cake\ORM\TableRegistry;
  20. use Cake\TestSuite\TestCase;
  21. use Cake\Utility\Time;
  22. /**
  23. * Test entity for mass assignment.
  24. */
  25. class OpenEntity extends Entity {
  26. protected $_accessible = [
  27. '*' => true,
  28. ];
  29. }
  30. /**
  31. * Test entity for mass assignment.
  32. */
  33. class ProtectedArticle extends Entity {
  34. protected $_accessible = [
  35. 'title' => true,
  36. 'body' => true
  37. ];
  38. }
  39. /**
  40. * Marshaller test case
  41. */
  42. class MarshallerTest extends TestCase {
  43. public $fixtures = ['core.tag', 'core.articles_tag', 'core.article', 'core.user', 'core.comment'];
  44. /**
  45. * setup
  46. *
  47. * @return void
  48. */
  49. public function setUp() {
  50. parent::setUp();
  51. $articles = TableRegistry::get('Articles');
  52. $articles->belongsTo('Users');
  53. $articles->hasMany('Comments');
  54. $articles->belongsToMany('Tags');
  55. $comments = TableRegistry::get('Comments');
  56. $users = TableRegistry::get('Users');
  57. $tags = TableRegistry::get('Tags');
  58. $articleTags = TableRegistry::get('ArticlesTags');
  59. $comments->belongsTo('Articles');
  60. $comments->belongsTo('Users');
  61. $articles->entityClass(__NAMESPACE__ . '\OpenEntity');
  62. $comments->entityClass(__NAMESPACE__ . '\OpenEntity');
  63. $users->entityClass(__NAMESPACE__ . '\OpenEntity');
  64. $tags->entityClass(__NAMESPACE__ . '\OpenEntity');
  65. $articleTags->entityClass(__NAMESPACE__ . '\OpenEntity');
  66. $this->articles = $articles;
  67. $this->comments = $comments;
  68. }
  69. /**
  70. * Teardown
  71. *
  72. * @return void
  73. */
  74. public function tearDown() {
  75. parent::tearDown();
  76. TableRegistry::clear();
  77. unset($this->articles, $this->comments);
  78. }
  79. /**
  80. * Test one() in a simple use.
  81. *
  82. * @return void
  83. */
  84. public function testOneSimple() {
  85. $data = [
  86. 'title' => 'My title',
  87. 'body' => 'My content',
  88. 'author_id' => 1,
  89. 'not_in_schema' => true
  90. ];
  91. $marshall = new Marshaller($this->articles);
  92. $result = $marshall->one($data, []);
  93. $this->assertInstanceOf('Cake\ORM\Entity', $result);
  94. $this->assertEquals($data, $result->toArray());
  95. $this->assertTrue($result->dirty(), 'Should be a dirty entity.');
  96. $this->assertNull($result->isNew(), 'Should be detached');
  97. $this->assertEquals('Articles', $result->source());
  98. }
  99. /**
  100. * Test marshalling datetime/date field.
  101. *
  102. * @return void
  103. */
  104. public function testOneWithDatetimeField() {
  105. $data = [
  106. 'comment' => 'My Comment text',
  107. 'created' => [
  108. 'year' => '2014',
  109. 'month' => '2',
  110. 'day' => 14
  111. ]
  112. ];
  113. $marshall = new Marshaller($this->comments);
  114. $result = $marshall->one($data, []);
  115. $this->assertEquals(new Time('2014-02-14 00:00:00'), $result->created);
  116. $data['created'] = [
  117. 'year' => '2014',
  118. 'month' => '2',
  119. 'day' => 14,
  120. 'hour' => 9,
  121. 'minute' => 25,
  122. 'meridian' => 'pm'
  123. ];
  124. $result = $marshall->one($data, []);
  125. $this->assertEquals(new Time('2014-02-14 21:25:00'), $result->created);
  126. $data['created'] = [
  127. 'year' => '2014',
  128. 'month' => '2',
  129. 'day' => 14,
  130. 'hour' => 9,
  131. 'minute' => 25,
  132. ];
  133. $result = $marshall->one($data, []);
  134. $this->assertEquals(new Time('2014-02-14 09:25:00'), $result->created);
  135. $data['created'] = '2014-02-14 09:25:00';
  136. $result = $marshall->one($data, []);
  137. $this->assertEquals(new Time('2014-02-14 09:25:00'), $result->created);
  138. $data['created'] = 1392387900;
  139. $result = $marshall->one($data, []);
  140. $this->assertEquals($data['created'], $result->created->getTimestamp());
  141. }
  142. /**
  143. * Test one() follows mass-assignment rules.
  144. *
  145. * @return void
  146. */
  147. public function testOneAccessibleProperties() {
  148. $data = [
  149. 'title' => 'My title',
  150. 'body' => 'My content',
  151. 'author_id' => 1,
  152. 'not_in_schema' => true
  153. ];
  154. $this->articles->entityClass(__NAMESPACE__ . '\ProtectedArticle');
  155. $marshall = new Marshaller($this->articles);
  156. $result = $marshall->one($data, []);
  157. $this->assertInstanceOf(__NAMESPACE__ . '\ProtectedArticle', $result);
  158. $this->assertNull($result->author_id);
  159. $this->assertNull($result->not_in_schema);
  160. }
  161. /**
  162. * test one() with a wrapping model name.
  163. *
  164. * @return void
  165. */
  166. public function testOneWithAdditionalName() {
  167. $data = [
  168. 'Articles' => [
  169. 'title' => 'My title',
  170. 'body' => 'My content',
  171. 'author_id' => 1,
  172. 'not_in_schema' => true,
  173. 'user' => [
  174. 'username' => 'mark',
  175. ]
  176. ]
  177. ];
  178. $marshall = new Marshaller($this->articles);
  179. $result = $marshall->one($data, ['Users']);
  180. $this->assertInstanceOf('Cake\ORM\Entity', $result);
  181. $this->assertTrue($result->dirty(), 'Should be a dirty entity.');
  182. $this->assertNull($result->isNew(), 'Should be detached');
  183. $this->assertEquals($data['Articles']['title'], $result->title);
  184. $this->assertEquals($data['Articles']['user']['username'], $result->user->username);
  185. }
  186. /**
  187. * test one() with association data.
  188. *
  189. * @return void
  190. */
  191. public function testOneAssociationsSingle() {
  192. $data = [
  193. 'title' => 'My title',
  194. 'body' => 'My content',
  195. 'author_id' => 1,
  196. 'comments' => [
  197. ['comment' => 'First post', 'user_id' => 2],
  198. ['comment' => 'Second post', 'user_id' => 2],
  199. ],
  200. 'user' => [
  201. 'username' => 'mark',
  202. 'password' => 'secret'
  203. ]
  204. ];
  205. $marshall = new Marshaller($this->articles);
  206. $result = $marshall->one($data, ['Users']);
  207. $this->assertEquals($data['title'], $result->title);
  208. $this->assertEquals($data['body'], $result->body);
  209. $this->assertEquals($data['author_id'], $result->author_id);
  210. $this->assertInternalType('array', $result->comments);
  211. $this->assertEquals($data['comments'], $result->comments);
  212. $this->assertInstanceOf('Cake\ORM\Entity', $result->user);
  213. $this->assertEquals($data['user']['username'], $result->user->username);
  214. $this->assertEquals($data['user']['password'], $result->user->password);
  215. }
  216. /**
  217. * test one() with association data.
  218. *
  219. * @return void
  220. */
  221. public function testOneAssociationsMany() {
  222. $data = [
  223. 'title' => 'My title',
  224. 'body' => 'My content',
  225. 'author_id' => 1,
  226. 'comments' => [
  227. ['comment' => 'First post', 'user_id' => 2],
  228. ['comment' => 'Second post', 'user_id' => 2],
  229. ],
  230. 'user' => [
  231. 'username' => 'mark',
  232. 'password' => 'secret'
  233. ]
  234. ];
  235. $marshall = new Marshaller($this->articles);
  236. $result = $marshall->one($data, ['Comments']);
  237. $this->assertEquals($data['title'], $result->title);
  238. $this->assertEquals($data['body'], $result->body);
  239. $this->assertEquals($data['author_id'], $result->author_id);
  240. $this->assertInternalType('array', $result->comments);
  241. $this->assertCount(2, $result->comments);
  242. $this->assertInstanceOf('Cake\ORM\Entity', $result->comments[0]);
  243. $this->assertInstanceOf('Cake\ORM\Entity', $result->comments[1]);
  244. $this->assertEquals($data['comments'][0]['comment'], $result->comments[0]->comment);
  245. $this->assertInternalType('array', $result->user);
  246. $this->assertEquals($data['user'], $result->user);
  247. }
  248. /**
  249. * Test building the _joinData entity for belongstomany associations.
  250. *
  251. * @return void
  252. */
  253. public function testOneBelongsToManyJoinData() {
  254. $data = [
  255. 'title' => 'My title',
  256. 'body' => 'My content',
  257. 'author_id' => 1,
  258. 'tags' => [
  259. ['tag' => 'news', '_joinData' => ['active' => 1]],
  260. ['tag' => 'cakephp', '_joinData' => ['active' => 0]],
  261. ],
  262. ];
  263. $marshall = new Marshaller($this->articles);
  264. $result = $marshall->one($data, [
  265. 'Tags' => [
  266. 'associated' => ['_joinData']
  267. ]
  268. ]);
  269. $this->assertEquals($data['title'], $result->title);
  270. $this->assertEquals($data['body'], $result->body);
  271. $this->assertInternalType('array', $result->tags);
  272. $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[0]);
  273. $this->assertEquals($data['tags'][0]['tag'], $result->tags[0]->tag);
  274. $this->assertInstanceOf(
  275. 'Cake\ORM\Entity',
  276. $result->tags[0]->_joinData,
  277. '_joinData should be an entity.'
  278. );
  279. $this->assertEquals(
  280. $data['tags'][0]['_joinData']['active'],
  281. $result->tags[0]->_joinData->active,
  282. '_joinData should be an entity.'
  283. );
  284. }
  285. /**
  286. * Test marshalling nested associations on the _joinData structure.
  287. *
  288. * @return void
  289. */
  290. public function testOneBelongsToManyJoinDataAssociated() {
  291. $data = [
  292. 'title' => 'My title',
  293. 'body' => 'My content',
  294. 'author_id' => 1,
  295. 'tags' => [
  296. [
  297. 'tag' => 'news',
  298. '_joinData' => [
  299. 'active' => 1,
  300. 'user' => ['username' => 'Bill'],
  301. ]
  302. ],
  303. [
  304. 'tag' => 'cakephp',
  305. '_joinData' => [
  306. 'active' => 0,
  307. 'user' => ['username' => 'Mark'],
  308. ]
  309. ],
  310. ],
  311. ];
  312. $articlesTags = TableRegistry::get('ArticlesTags');
  313. $articlesTags->belongsTo('Users');
  314. $marshall = new Marshaller($this->articles);
  315. $result = $marshall->one($data, [
  316. 'Tags' => [
  317. 'associated' => [
  318. '_joinData' => ['associated' => ['Users']]
  319. ]
  320. ]
  321. ]);
  322. $this->assertInstanceOf(
  323. 'Cake\ORM\Entity',
  324. $result->tags[0]->_joinData->user,
  325. 'joinData should contain a user entity.'
  326. );
  327. $this->assertEquals('Bill', $result->tags[0]->_joinData->user->username);
  328. $this->assertInstanceOf(
  329. 'Cake\ORM\Entity',
  330. $result->tags[1]->_joinData->user,
  331. 'joinData should contain a user entity.'
  332. );
  333. $this->assertEquals('Mark', $result->tags[1]->_joinData->user->username);
  334. }
  335. /**
  336. * Test one() with deeper associations.
  337. *
  338. * @return void
  339. */
  340. public function testOneDeepAssociations() {
  341. $data = [
  342. 'comment' => 'First post',
  343. 'user_id' => 2,
  344. 'article' => [
  345. 'title' => 'Article title',
  346. 'body' => 'Article body',
  347. 'user' => [
  348. 'username' => 'mark',
  349. 'password' => 'secret'
  350. ],
  351. ]
  352. ];
  353. $marshall = new Marshaller($this->comments);
  354. $result = $marshall->one($data, ['Articles' => ['associated' => ['Users']]]);
  355. $this->assertEquals(
  356. $data['article']['title'],
  357. $result->article->title
  358. );
  359. $this->assertEquals(
  360. $data['article']['user']['username'],
  361. $result->article->user->username
  362. );
  363. }
  364. /**
  365. * Test many() with a simple set of data.
  366. *
  367. * @return void
  368. */
  369. public function testManySimple() {
  370. $data = [
  371. ['comment' => 'First post', 'user_id' => 2],
  372. ['comment' => 'Second post', 'user_id' => 2],
  373. ];
  374. $marshall = new Marshaller($this->comments);
  375. $result = $marshall->many($data);
  376. $this->assertCount(2, $result);
  377. $this->assertInstanceOf('Cake\ORM\Entity', $result[0]);
  378. $this->assertInstanceOf('Cake\ORM\Entity', $result[1]);
  379. $this->assertEquals($data[0]['comment'], $result[0]->comment);
  380. $this->assertEquals($data[1]['comment'], $result[1]->comment);
  381. }
  382. /**
  383. * test many() with nested associations.
  384. *
  385. * @return void
  386. */
  387. public function testManyAssociations() {
  388. $data = [
  389. [
  390. 'comment' => 'First post',
  391. 'user_id' => 2,
  392. 'user' => [
  393. 'username' => 'mark',
  394. ],
  395. ],
  396. [
  397. 'comment' => 'Second post',
  398. 'user_id' => 2,
  399. 'user' => [
  400. 'username' => 'jose',
  401. ],
  402. ],
  403. ];
  404. $marshall = new Marshaller($this->comments);
  405. $result = $marshall->many($data, ['Users']);
  406. $this->assertCount(2, $result);
  407. $this->assertInstanceOf('Cake\ORM\Entity', $result[0]);
  408. $this->assertInstanceOf('Cake\ORM\Entity', $result[1]);
  409. $this->assertEquals(
  410. $data[0]['user']['username'],
  411. $result[0]->user->username
  412. );
  413. $this->assertEquals(
  414. $data[1]['user']['username'],
  415. $result[1]->user->username
  416. );
  417. }
  418. /**
  419. * Test generating a list of entities from a list of ids.
  420. *
  421. * @return void
  422. */
  423. public function testOneGenerateBelongsToManyEntitiesFromIds() {
  424. $data = [
  425. 'title' => 'Haz tags',
  426. 'body' => 'Some content here',
  427. 'tags' => ['_ids' => [1, 2, 3]]
  428. ];
  429. $marshall = new Marshaller($this->articles);
  430. $result = $marshall->one($data, ['Tags']);
  431. $this->assertCount(3, $result->tags);
  432. $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[0]);
  433. $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[1]);
  434. $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[2]);
  435. }
  436. /**
  437. * Test merge() in a simple use.
  438. *
  439. * @return void
  440. */
  441. public function testMergeSimple() {
  442. $data = [
  443. 'title' => 'My title',
  444. 'author_id' => 1,
  445. 'not_in_schema' => true
  446. ];
  447. $marshall = new Marshaller($this->articles);
  448. $entity = new Entity([
  449. 'title' => 'Foo',
  450. 'body' => 'My Content'
  451. ]);
  452. $entity->accessible('*', true);
  453. $entity->isNew(false);
  454. $entity->clean();
  455. $result = $marshall->merge($entity, $data, []);
  456. $this->assertSame($entity, $result);
  457. $this->assertEquals($data + ['body' => 'My Content'], $result->toArray());
  458. $this->assertTrue($result->dirty(), 'Should be a dirty entity.');
  459. $this->assertFalse($result->isNew(), 'Should not change the entity state');
  460. }
  461. /**
  462. * Tests that merge respects the entity accessible methods
  463. *
  464. * @return void
  465. */
  466. public function testMergeWhitelist() {
  467. $data = [
  468. 'title' => 'My title',
  469. 'author_id' => 1,
  470. 'not_in_schema' => true
  471. ];
  472. $marshall = new Marshaller($this->articles);
  473. $entity = new Entity([
  474. 'title' => 'Foo',
  475. 'body' => 'My Content'
  476. ]);
  477. $entity->accessible('*', false);
  478. $entity->accessible('author_id', true);
  479. $entity->isNew(false);
  480. $result = $marshall->merge($entity, $data, []);
  481. $expected = [
  482. 'title' => 'Foo',
  483. 'body' => 'My Content',
  484. 'author_id' => 1
  485. ];
  486. $this->assertEquals($expected, $result->toArray());
  487. }
  488. /**
  489. * Tests that fields with the same value are not marked as dirty
  490. *
  491. * @return void
  492. */
  493. public function testMergeDirty() {
  494. $marshall = new Marshaller($this->articles);
  495. $entity = new Entity([
  496. 'title' => 'Foo',
  497. 'author_id' => 1
  498. ]);
  499. $data = [
  500. 'title' => 'Foo',
  501. 'author_id' => 1,
  502. 'crazy' => true
  503. ];
  504. $entity->accessible('*', true);
  505. $entity->clean();
  506. $result = $marshall->merge($entity, $data, []);
  507. $expected = [
  508. 'title' => 'Foo',
  509. 'author_id' => 1,
  510. 'crazy' => true
  511. ];
  512. $this->assertEquals($expected, $result->toArray());
  513. $this->assertFalse($entity->dirty('title'));
  514. $this->assertFalse($entity->dirty('author_id'));
  515. $this->assertTrue($entity->dirty('crazy'));
  516. }
  517. /**
  518. * Tests merging data into an associated entity
  519. *
  520. * @return void
  521. */
  522. public function testMergeWithSingleAssociation() {
  523. $user = new Entity([
  524. 'username' => 'mark',
  525. 'password' => 'secret'
  526. ]);
  527. $entity = new Entity([
  528. 'tile' => 'My Title',
  529. 'user' => $user
  530. ]);
  531. $user->accessible('*', true);
  532. $entity->accessible('*', true);
  533. $data = [
  534. 'body' => 'My Content',
  535. 'user' => [
  536. 'password' => 'not a secret'
  537. ]
  538. ];
  539. $marshall = new Marshaller($this->articles);
  540. $marshall->merge($entity, $data, ['Users']);
  541. $this->assertEquals('My Content', $entity->body);
  542. $this->assertSame($user, $entity->user);
  543. $this->assertEquals('mark', $entity->user->username);
  544. $this->assertEquals('not a secret', $entity->user->password);
  545. $this->assertTrue($entity->dirty('user'));
  546. }
  547. /**
  548. * Tests that new associated entities can be created when merging data into
  549. * a parent entity
  550. *
  551. * @return void
  552. */
  553. public function testMergeCreateAssociation() {
  554. $entity = new Entity([
  555. 'tile' => 'My Title'
  556. ]);
  557. $entity->accessible('*', true);
  558. $data = [
  559. 'body' => 'My Content',
  560. 'user' => [
  561. 'username' => 'mark',
  562. 'password' => 'not a secret'
  563. ]
  564. ];
  565. $marshall = new Marshaller($this->articles);
  566. $marshall->merge($entity, $data, ['Users']);
  567. $this->assertEquals('My Content', $entity->body);
  568. $this->assertInstanceOf('Cake\ORM\Entity', $entity->user);
  569. $this->assertEquals('mark', $entity->user->username);
  570. $this->assertEquals('not a secret', $entity->user->password);
  571. $this->assertTrue($entity->dirty('user'));
  572. $this->assertNull($entity->user->isNew());
  573. }
  574. /**
  575. * Tests merging one to many associations
  576. *
  577. * @return void
  578. */
  579. public function testMergeMultipleAssociations() {
  580. $user = new Entity(['username' => 'mark', 'password' => 'secret']);
  581. $comment1 = new Entity(['id' => 1, 'comment' => 'A comment']);
  582. $comment2 = new Entity(['id' => 2, 'comment' => 'Another comment']);
  583. $entity = new Entity([
  584. 'title' => 'My Title',
  585. 'user' => $user,
  586. 'comments' => [$comment1, $comment2]
  587. ]);
  588. $user->accessible('*', true);
  589. $comment1->accessible('*', true);
  590. $comment2->accessible('*', true);
  591. $entity->accessible('*', true);
  592. $data = [
  593. 'title' => 'Another title',
  594. 'user' => ['password' => 'not so secret'],
  595. 'comments' => [
  596. ['comment' => 'Extra comment 1'],
  597. ['id' => 2, 'comment' => 'Altered comment 2'],
  598. ['id' => 1, 'comment' => 'Altered comment 1'],
  599. ['id' => 3, 'comment' => 'Extra comment 3'],
  600. ['comment' => 'Extra comment 2']
  601. ]
  602. ];
  603. $marshall = new Marshaller($this->articles);
  604. $result = $marshall->merge($entity, $data, ['Users', 'Comments']);
  605. $this->assertSame($entity, $result);
  606. $this->assertSame($user, $result->user);
  607. $this->assertEquals('not so secret', $entity->user->password);
  608. $this->assertSame($comment1, $entity->comments[0]);
  609. $this->assertSame($comment2, $entity->comments[1]);
  610. $this->assertEquals('Altered comment 1', $entity->comments[0]->comment);
  611. $this->assertEquals('Altered comment 2', $entity->comments[1]->comment);
  612. $this->assertEquals(
  613. ['comment' => 'Extra comment 3', 'id' => 3],
  614. $entity->comments[2]->toArray()
  615. );
  616. $this->assertEquals(
  617. ['comment' => 'Extra comment 1'],
  618. $entity->comments[3]->toArray()
  619. );
  620. $this->assertEquals(
  621. ['comment' => 'Extra comment 2'],
  622. $entity->comments[4]->toArray()
  623. );
  624. }
  625. /**
  626. * Tests that merging data to an entity containing belongsToMany and _ids
  627. * will just overwrite the data
  628. *
  629. * @return void
  630. */
  631. public function testMergeBelongsToManyEntitiesFromIds() {
  632. $entity = new Entity([
  633. 'title' => 'Haz tags',
  634. 'body' => 'Some content here',
  635. 'tags' => [
  636. new Entity(['id' => 1, 'name' => 'Cake']),
  637. new Entity(['id' => 2, 'name' => 'PHP'])
  638. ]
  639. ]);
  640. $data = [
  641. 'title' => 'Haz moar tags',
  642. 'tags' => ['_ids' => [1, 2, 3]]
  643. ];
  644. $entity->accessible('*', true);
  645. $marshall = new Marshaller($this->articles);
  646. $result = $marshall->merge($entity, $data, ['Tags']);
  647. $this->assertCount(3, $result->tags);
  648. $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[0]);
  649. $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[1]);
  650. $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[2]);
  651. }
  652. /**
  653. * Test merging the _joinData entity for belongstomany associations.
  654. *
  655. * @return void
  656. */
  657. public function testMergeBelongsToManyJoinData() {
  658. $data = [
  659. 'title' => 'My title',
  660. 'body' => 'My content',
  661. 'author_id' => 1,
  662. 'tags' => [
  663. [
  664. 'id' => 1,
  665. 'tag' => 'news',
  666. '_joinData' => [
  667. 'active' => 0
  668. ]
  669. ],
  670. [
  671. 'id' => 2,
  672. 'tag' => 'cakephp',
  673. '_joinData' => [
  674. 'active' => 0
  675. ]
  676. ],
  677. ],
  678. ];
  679. $options = ['Tags' => ['associated' => ['_joinData']]];
  680. $marshall = new Marshaller($this->articles);
  681. $entity = $marshall->one($data, $options);
  682. $entity->accessible('*', true);
  683. $data = [
  684. 'title' => 'Haz data',
  685. 'tags' => [
  686. ['id' => 1, 'tag' => 'Cake', '_joinData' => ['foo' => 'bar']],
  687. ['tag' => 'new tag', '_joinData' => ['active' => 1, 'foo' => 'baz']]
  688. ]
  689. ];
  690. $tag1 = $entity->tags[0];
  691. $result = $marshall->merge($entity, $data, $options);
  692. $this->assertEquals($data['title'], $result->title);
  693. $this->assertEquals('My content', $result->body);
  694. $this->assertSame($tag1, $entity->tags[0]);
  695. $this->assertSame($tag1->_joinData, $entity->tags[0]->_joinData);
  696. $this->assertSame(
  697. ['active' => 0, 'foo' => 'bar'],
  698. $entity->tags[0]->_joinData->toArray()
  699. );
  700. $this->assertSame(
  701. ['active' => 1, 'foo' => 'baz'],
  702. $entity->tags[1]->_joinData->toArray()
  703. );
  704. $this->assertEquals('new tag', $entity->tags[1]->tag);
  705. $this->assertTrue($entity->tags[0]->dirty('_joinData'));
  706. $this->assertTrue($entity->tags[1]->dirty('_joinData'));
  707. }
  708. /**
  709. * Test merging associations inside _joinData
  710. *
  711. * @return void
  712. */
  713. public function testMergeJoinDataAssociations() {
  714. $data = [
  715. 'title' => 'My title',
  716. 'body' => 'My content',
  717. 'author_id' => 1,
  718. 'tags' => [
  719. [
  720. 'id' => 1,
  721. 'tag' => 'news',
  722. '_joinData' => [
  723. 'active' => 0,
  724. 'user' => ['username' => 'Bill']
  725. ]
  726. ],
  727. [
  728. 'id' => 2,
  729. 'tag' => 'cakephp',
  730. '_joinData' => [
  731. 'active' => 0
  732. ]
  733. ],
  734. ]
  735. ];
  736. $articlesTags = TableRegistry::get('ArticlesTags');
  737. $articlesTags->belongsTo('Users');
  738. $options = [
  739. 'Tags' => [
  740. 'associated' => [
  741. '_joinData' => ['associated' => ['Users']]
  742. ]
  743. ]
  744. ];
  745. $marshall = new Marshaller($this->articles);
  746. $entity = $marshall->one($data, $options);
  747. $entity->accessible('*', true);
  748. $data = [
  749. 'title' => 'Haz data',
  750. 'tags' => [
  751. [
  752. 'id' => 1,
  753. 'tag' => 'news',
  754. '_joinData' => [
  755. 'foo' => 'bar',
  756. 'user' => ['password' => 'secret']
  757. ]
  758. ],
  759. [
  760. 'id' => 2,
  761. '_joinData' => [
  762. 'active' => 1,
  763. 'foo' => 'baz',
  764. 'user' => ['username' => 'ber']
  765. ]
  766. ]
  767. ]
  768. ];
  769. $tag1 = $entity->tags[0];
  770. $result = $marshall->merge($entity, $data, $options);
  771. $this->assertEquals($data['title'], $result->title);
  772. $this->assertEquals('My content', $result->body);
  773. $this->assertSame($tag1, $entity->tags[0]);
  774. $this->assertSame($tag1->_joinData, $entity->tags[0]->_joinData);
  775. $this->assertEquals('Bill', $entity->tags[0]->_joinData->user->username);
  776. $this->assertEquals('secret', $entity->tags[0]->_joinData->user->password);
  777. $this->assertEquals('ber', $entity->tags[1]->_joinData->user->username);
  778. }
  779. /**
  780. * Test mergeMany() with a simple set of data.
  781. *
  782. * @return void
  783. */
  784. public function testMergeManySimple() {
  785. $entities = [
  786. new OpenEntity(['id' => 1, 'comment' => 'First post', 'user_id' => 2]),
  787. new OpenEntity(['id' => 2, 'comment' => 'Second post', 'user_id' => 2])
  788. ];
  789. $entities[0]->clean();
  790. $entities[1]->clean();
  791. $data = [
  792. ['id' => 2, 'comment' => 'Changed 2', 'user_id' => 2],
  793. ['id' => 1, 'comment' => 'Changed 1', 'user_id' => 1]
  794. ];
  795. $marshall = new Marshaller($this->comments);
  796. $result = $marshall->mergeMany($entities, $data);
  797. $this->assertSame($entities[0], $result[0]);
  798. $this->assertSame($entities[1], $result[1]);
  799. $this->assertEquals('Changed 1', $result[0]->comment);
  800. $this->assertEquals(1, $result[0]->user_id);
  801. $this->assertEquals('Changed 2', $result[1]->comment);
  802. $this->assertTrue($result[0]->dirty('user_id'));
  803. $this->assertFalse($result[1]->dirty('user_id'));
  804. }
  805. /**
  806. * Tests that only records found in the data array are returned, those that cannot
  807. * be matched are discarded
  808. *
  809. * @return void
  810. */
  811. public function testMergeManyWithAppend() {
  812. $entities = [
  813. new OpenEntity(['comment' => 'First post', 'user_id' => 2]),
  814. new OpenEntity(['id' => 2, 'comment' => 'Second post', 'user_id' => 2])
  815. ];
  816. $entities[0]->clean();
  817. $entities[1]->clean();
  818. $data = [
  819. ['id' => 2, 'comment' => 'Changed 2', 'user_id' => 2],
  820. ['id' => 1, 'comment' => 'Comment 1', 'user_id' => 1]
  821. ];
  822. $marshall = new Marshaller($this->comments);
  823. $result = $marshall->mergeMany($entities, $data);
  824. $this->assertCount(2, $result);
  825. $this->assertNotSame($entities[0], $result[0]);
  826. $this->assertSame($entities[1], $result[0]);
  827. $this->assertEquals('Changed 2', $result[0]->comment);
  828. }
  829. /**
  830. * Tests merge with data types that need to be marshalled
  831. *
  832. * @return void
  833. */
  834. public function testMergeComplexType() {
  835. $entity = new Entity(
  836. ['comment' => 'My Comment text'],
  837. ['markNew' => false, 'markClean' => true]
  838. );
  839. $data = [
  840. 'created' => [
  841. 'year' => '2014',
  842. 'month' => '2',
  843. 'day' => 14
  844. ]
  845. ];
  846. $marshall = new Marshaller($this->comments);
  847. $result = $marshall->merge($entity, $data);
  848. $this->assertInstanceOf('DateTime', $entity->created);
  849. $this->assertEquals('2014-02-14', $entity->created->format('Y-m-d'));
  850. }
  851. }