MarshallerTest.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943
  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 http://www.opensource.org/licenses/mit-license.php MIT License
  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' => '']
  428. ];
  429. $marshall = new Marshaller($this->articles);
  430. $result = $marshall->one($data, ['Tags']);
  431. $this->assertCount(0, $result->tags);
  432. $data = [
  433. 'title' => 'Haz tags',
  434. 'body' => 'Some content here',
  435. 'tags' => ['_ids' => [1, 2, 3]]
  436. ];
  437. $marshall = new Marshaller($this->articles);
  438. $result = $marshall->one($data, ['Tags']);
  439. $this->assertCount(3, $result->tags);
  440. $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[0]);
  441. $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[1]);
  442. $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[2]);
  443. }
  444. /**
  445. * Test merge() in a simple use.
  446. *
  447. * @return void
  448. */
  449. public function testMergeSimple() {
  450. $data = [
  451. 'title' => 'My title',
  452. 'author_id' => 1,
  453. 'not_in_schema' => true
  454. ];
  455. $marshall = new Marshaller($this->articles);
  456. $entity = new Entity([
  457. 'title' => 'Foo',
  458. 'body' => 'My Content'
  459. ]);
  460. $entity->accessible('*', true);
  461. $entity->isNew(false);
  462. $entity->clean();
  463. $result = $marshall->merge($entity, $data, []);
  464. $this->assertSame($entity, $result);
  465. $this->assertEquals($data + ['body' => 'My Content'], $result->toArray());
  466. $this->assertTrue($result->dirty(), 'Should be a dirty entity.');
  467. $this->assertFalse($result->isNew(), 'Should not change the entity state');
  468. }
  469. /**
  470. * Tests that merge respects the entity accessible methods
  471. *
  472. * @return void
  473. */
  474. public function testMergeWhitelist() {
  475. $data = [
  476. 'title' => 'My title',
  477. 'author_id' => 1,
  478. 'not_in_schema' => true
  479. ];
  480. $marshall = new Marshaller($this->articles);
  481. $entity = new Entity([
  482. 'title' => 'Foo',
  483. 'body' => 'My Content'
  484. ]);
  485. $entity->accessible('*', false);
  486. $entity->accessible('author_id', true);
  487. $entity->isNew(false);
  488. $result = $marshall->merge($entity, $data, []);
  489. $expected = [
  490. 'title' => 'Foo',
  491. 'body' => 'My Content',
  492. 'author_id' => 1
  493. ];
  494. $this->assertEquals($expected, $result->toArray());
  495. }
  496. /**
  497. * Tests that fields with the same value are not marked as dirty
  498. *
  499. * @return void
  500. */
  501. public function testMergeDirty() {
  502. $marshall = new Marshaller($this->articles);
  503. $entity = new Entity([
  504. 'title' => 'Foo',
  505. 'author_id' => 1
  506. ]);
  507. $data = [
  508. 'title' => 'Foo',
  509. 'author_id' => 1,
  510. 'crazy' => true
  511. ];
  512. $entity->accessible('*', true);
  513. $entity->clean();
  514. $result = $marshall->merge($entity, $data, []);
  515. $expected = [
  516. 'title' => 'Foo',
  517. 'author_id' => 1,
  518. 'crazy' => true
  519. ];
  520. $this->assertEquals($expected, $result->toArray());
  521. $this->assertFalse($entity->dirty('title'));
  522. $this->assertFalse($entity->dirty('author_id'));
  523. $this->assertTrue($entity->dirty('crazy'));
  524. }
  525. /**
  526. * Tests merging data into an associated entity
  527. *
  528. * @return void
  529. */
  530. public function testMergeWithSingleAssociation() {
  531. $user = new Entity([
  532. 'username' => 'mark',
  533. 'password' => 'secret'
  534. ]);
  535. $entity = new Entity([
  536. 'tile' => 'My Title',
  537. 'user' => $user
  538. ]);
  539. $user->accessible('*', true);
  540. $entity->accessible('*', true);
  541. $data = [
  542. 'body' => 'My Content',
  543. 'user' => [
  544. 'password' => 'not a secret'
  545. ]
  546. ];
  547. $marshall = new Marshaller($this->articles);
  548. $marshall->merge($entity, $data, ['Users']);
  549. $this->assertEquals('My Content', $entity->body);
  550. $this->assertSame($user, $entity->user);
  551. $this->assertEquals('mark', $entity->user->username);
  552. $this->assertEquals('not a secret', $entity->user->password);
  553. $this->assertTrue($entity->dirty('user'));
  554. }
  555. /**
  556. * Tests that new associated entities can be created when merging data into
  557. * a parent entity
  558. *
  559. * @return void
  560. */
  561. public function testMergeCreateAssociation() {
  562. $entity = new Entity([
  563. 'tile' => 'My Title'
  564. ]);
  565. $entity->accessible('*', true);
  566. $data = [
  567. 'body' => 'My Content',
  568. 'user' => [
  569. 'username' => 'mark',
  570. 'password' => 'not a secret'
  571. ]
  572. ];
  573. $marshall = new Marshaller($this->articles);
  574. $marshall->merge($entity, $data, ['Users']);
  575. $this->assertEquals('My Content', $entity->body);
  576. $this->assertInstanceOf('Cake\ORM\Entity', $entity->user);
  577. $this->assertEquals('mark', $entity->user->username);
  578. $this->assertEquals('not a secret', $entity->user->password);
  579. $this->assertTrue($entity->dirty('user'));
  580. $this->assertNull($entity->user->isNew());
  581. }
  582. /**
  583. * Tests merging one to many associations
  584. *
  585. * @return void
  586. */
  587. public function testMergeMultipleAssociations() {
  588. $user = new Entity(['username' => 'mark', 'password' => 'secret']);
  589. $comment1 = new Entity(['id' => 1, 'comment' => 'A comment']);
  590. $comment2 = new Entity(['id' => 2, 'comment' => 'Another comment']);
  591. $entity = new Entity([
  592. 'title' => 'My Title',
  593. 'user' => $user,
  594. 'comments' => [$comment1, $comment2]
  595. ]);
  596. $user->accessible('*', true);
  597. $comment1->accessible('*', true);
  598. $comment2->accessible('*', true);
  599. $entity->accessible('*', true);
  600. $data = [
  601. 'title' => 'Another title',
  602. 'user' => ['password' => 'not so secret'],
  603. 'comments' => [
  604. ['comment' => 'Extra comment 1'],
  605. ['id' => 2, 'comment' => 'Altered comment 2'],
  606. ['id' => 1, 'comment' => 'Altered comment 1'],
  607. ['id' => 3, 'comment' => 'Extra comment 3'],
  608. ['comment' => 'Extra comment 2']
  609. ]
  610. ];
  611. $marshall = new Marshaller($this->articles);
  612. $result = $marshall->merge($entity, $data, ['Users', 'Comments']);
  613. $this->assertSame($entity, $result);
  614. $this->assertSame($user, $result->user);
  615. $this->assertEquals('not so secret', $entity->user->password);
  616. $this->assertSame($comment1, $entity->comments[0]);
  617. $this->assertSame($comment2, $entity->comments[1]);
  618. $this->assertEquals('Altered comment 1', $entity->comments[0]->comment);
  619. $this->assertEquals('Altered comment 2', $entity->comments[1]->comment);
  620. $this->assertEquals(
  621. ['comment' => 'Extra comment 3', 'id' => 3],
  622. $entity->comments[2]->toArray()
  623. );
  624. $this->assertEquals(
  625. ['comment' => 'Extra comment 1'],
  626. $entity->comments[3]->toArray()
  627. );
  628. $this->assertEquals(
  629. ['comment' => 'Extra comment 2'],
  630. $entity->comments[4]->toArray()
  631. );
  632. }
  633. /**
  634. * Tests that merging data to an entity containing belongsToMany and _ids
  635. * will just overwrite the data
  636. *
  637. * @return void
  638. */
  639. public function testMergeBelongsToManyEntitiesFromIds() {
  640. $entity = new Entity([
  641. 'title' => 'Haz tags',
  642. 'body' => 'Some content here',
  643. 'tags' => [
  644. new Entity(['id' => 1, 'name' => 'Cake']),
  645. new Entity(['id' => 2, 'name' => 'PHP'])
  646. ]
  647. ]);
  648. $data = [
  649. 'title' => 'Haz moar tags',
  650. 'tags' => ['_ids' => [1, 2, 3]]
  651. ];
  652. $entity->accessible('*', true);
  653. $marshall = new Marshaller($this->articles);
  654. $result = $marshall->merge($entity, $data, ['Tags']);
  655. $this->assertCount(3, $result->tags);
  656. $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[0]);
  657. $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[1]);
  658. $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[2]);
  659. }
  660. /**
  661. * Test merging the _joinData entity for belongstomany associations.
  662. *
  663. * @return void
  664. */
  665. public function testMergeBelongsToManyJoinData() {
  666. $data = [
  667. 'title' => 'My title',
  668. 'body' => 'My content',
  669. 'author_id' => 1,
  670. 'tags' => [
  671. [
  672. 'id' => 1,
  673. 'tag' => 'news',
  674. '_joinData' => [
  675. 'active' => 0
  676. ]
  677. ],
  678. [
  679. 'id' => 2,
  680. 'tag' => 'cakephp',
  681. '_joinData' => [
  682. 'active' => 0
  683. ]
  684. ],
  685. ],
  686. ];
  687. $options = ['Tags' => ['associated' => ['_joinData']]];
  688. $marshall = new Marshaller($this->articles);
  689. $entity = $marshall->one($data, $options);
  690. $entity->accessible('*', true);
  691. $data = [
  692. 'title' => 'Haz data',
  693. 'tags' => [
  694. ['id' => 1, 'tag' => 'Cake', '_joinData' => ['foo' => 'bar']],
  695. ['tag' => 'new tag', '_joinData' => ['active' => 1, 'foo' => 'baz']]
  696. ]
  697. ];
  698. $tag1 = $entity->tags[0];
  699. $result = $marshall->merge($entity, $data, $options);
  700. $this->assertEquals($data['title'], $result->title);
  701. $this->assertEquals('My content', $result->body);
  702. $this->assertSame($tag1, $entity->tags[0]);
  703. $this->assertSame($tag1->_joinData, $entity->tags[0]->_joinData);
  704. $this->assertSame(
  705. ['active' => 0, 'foo' => 'bar'],
  706. $entity->tags[0]->_joinData->toArray()
  707. );
  708. $this->assertSame(
  709. ['active' => 1, 'foo' => 'baz'],
  710. $entity->tags[1]->_joinData->toArray()
  711. );
  712. $this->assertEquals('new tag', $entity->tags[1]->tag);
  713. $this->assertTrue($entity->tags[0]->dirty('_joinData'));
  714. $this->assertTrue($entity->tags[1]->dirty('_joinData'));
  715. }
  716. /**
  717. * Test merging associations inside _joinData
  718. *
  719. * @return void
  720. */
  721. public function testMergeJoinDataAssociations() {
  722. $data = [
  723. 'title' => 'My title',
  724. 'body' => 'My content',
  725. 'author_id' => 1,
  726. 'tags' => [
  727. [
  728. 'id' => 1,
  729. 'tag' => 'news',
  730. '_joinData' => [
  731. 'active' => 0,
  732. 'user' => ['username' => 'Bill']
  733. ]
  734. ],
  735. [
  736. 'id' => 2,
  737. 'tag' => 'cakephp',
  738. '_joinData' => [
  739. 'active' => 0
  740. ]
  741. ],
  742. ]
  743. ];
  744. $articlesTags = TableRegistry::get('ArticlesTags');
  745. $articlesTags->belongsTo('Users');
  746. $options = [
  747. 'Tags' => [
  748. 'associated' => [
  749. '_joinData' => ['associated' => ['Users']]
  750. ]
  751. ]
  752. ];
  753. $marshall = new Marshaller($this->articles);
  754. $entity = $marshall->one($data, $options);
  755. $entity->accessible('*', true);
  756. $data = [
  757. 'title' => 'Haz data',
  758. 'tags' => [
  759. [
  760. 'id' => 1,
  761. 'tag' => 'news',
  762. '_joinData' => [
  763. 'foo' => 'bar',
  764. 'user' => ['password' => 'secret']
  765. ]
  766. ],
  767. [
  768. 'id' => 2,
  769. '_joinData' => [
  770. 'active' => 1,
  771. 'foo' => 'baz',
  772. 'user' => ['username' => 'ber']
  773. ]
  774. ]
  775. ]
  776. ];
  777. $tag1 = $entity->tags[0];
  778. $result = $marshall->merge($entity, $data, $options);
  779. $this->assertEquals($data['title'], $result->title);
  780. $this->assertEquals('My content', $result->body);
  781. $this->assertSame($tag1, $entity->tags[0]);
  782. $this->assertSame($tag1->_joinData, $entity->tags[0]->_joinData);
  783. $this->assertEquals('Bill', $entity->tags[0]->_joinData->user->username);
  784. $this->assertEquals('secret', $entity->tags[0]->_joinData->user->password);
  785. $this->assertEquals('ber', $entity->tags[1]->_joinData->user->username);
  786. }
  787. /**
  788. * Test mergeMany() with a simple set of data.
  789. *
  790. * @return void
  791. */
  792. public function testMergeManySimple() {
  793. $entities = [
  794. new OpenEntity(['id' => 1, 'comment' => 'First post', 'user_id' => 2]),
  795. new OpenEntity(['id' => 2, 'comment' => 'Second post', 'user_id' => 2])
  796. ];
  797. $entities[0]->clean();
  798. $entities[1]->clean();
  799. $data = [
  800. ['id' => 2, 'comment' => 'Changed 2', 'user_id' => 2],
  801. ['id' => 1, 'comment' => 'Changed 1', 'user_id' => 1]
  802. ];
  803. $marshall = new Marshaller($this->comments);
  804. $result = $marshall->mergeMany($entities, $data);
  805. $this->assertSame($entities[0], $result[0]);
  806. $this->assertSame($entities[1], $result[1]);
  807. $this->assertEquals('Changed 1', $result[0]->comment);
  808. $this->assertEquals(1, $result[0]->user_id);
  809. $this->assertEquals('Changed 2', $result[1]->comment);
  810. $this->assertTrue($result[0]->dirty('user_id'));
  811. $this->assertFalse($result[1]->dirty('user_id'));
  812. }
  813. /**
  814. * Tests that only records found in the data array are returned, those that cannot
  815. * be matched are discarded
  816. *
  817. * @return void
  818. */
  819. public function testMergeManyWithAppend() {
  820. $entities = [
  821. new OpenEntity(['comment' => 'First post', 'user_id' => 2]),
  822. new OpenEntity(['id' => 2, 'comment' => 'Second post', 'user_id' => 2])
  823. ];
  824. $entities[0]->clean();
  825. $entities[1]->clean();
  826. $data = [
  827. ['id' => 2, 'comment' => 'Changed 2', 'user_id' => 2],
  828. ['id' => 1, 'comment' => 'Comment 1', 'user_id' => 1]
  829. ];
  830. $marshall = new Marshaller($this->comments);
  831. $result = $marshall->mergeMany($entities, $data);
  832. $this->assertCount(2, $result);
  833. $this->assertNotSame($entities[0], $result[0]);
  834. $this->assertSame($entities[1], $result[0]);
  835. $this->assertEquals('Changed 2', $result[0]->comment);
  836. }
  837. /**
  838. * Tests merge with data types that need to be marshalled
  839. *
  840. * @return void
  841. */
  842. public function testMergeComplexType() {
  843. $entity = new Entity(
  844. ['comment' => 'My Comment text'],
  845. ['markNew' => false, 'markClean' => true]
  846. );
  847. $data = [
  848. 'created' => [
  849. 'year' => '2014',
  850. 'month' => '2',
  851. 'day' => 14
  852. ]
  853. ];
  854. $marshall = new Marshaller($this->comments);
  855. $result = $marshall->merge($entity, $data);
  856. $this->assertInstanceOf('DateTime', $entity->created);
  857. $this->assertEquals('2014-02-14', $entity->created->format('Y-m-d'));
  858. }
  859. }