EntityTest.php 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116
  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\TestSuite\TestCase;
  18. use Cake\Validation\Validator;
  19. /**
  20. * Entity test case.
  21. */
  22. class EntityTest extends TestCase {
  23. /**
  24. * Tests setting a single property in an entity without custom setters
  25. *
  26. * @return void
  27. */
  28. public function testSetOneParamNoSetters() {
  29. $entity = new Entity;
  30. $entity->set('foo', 'bar');
  31. $this->assertEquals('bar', $entity->foo);
  32. $entity->set('foo', 'baz');
  33. $this->assertEquals('baz', $entity->foo);
  34. $entity->set('id', 1);
  35. $this->assertSame(1, $entity->id);
  36. }
  37. /**
  38. * Tests setting multiple properties without custom setters
  39. *
  40. * @return void
  41. */
  42. public function testSetMultiplePropertiesNoSetters() {
  43. $entity = new Entity;
  44. $entity->accessible('*', true);
  45. $entity->set(['foo' => 'bar', 'id' => 1]);
  46. $this->assertEquals('bar', $entity->foo);
  47. $this->assertSame(1, $entity->id);
  48. $entity->set(['foo' => 'baz', 'id' => 2, 'thing' => 3]);
  49. $this->assertEquals('baz', $entity->foo);
  50. $this->assertSame(2, $entity->id);
  51. $this->assertSame(3, $entity->thing);
  52. }
  53. /**
  54. * Tests setting a single property using a setter function
  55. *
  56. * @return void
  57. */
  58. public function testSetOneParamWithSetter() {
  59. $entity = $this->getMock('\Cake\ORM\Entity', ['_setName']);
  60. $entity->expects($this->once())->method('_setName')
  61. ->with('Jones')
  62. ->will($this->returnCallback(function ($name) {
  63. $this->assertEquals('Jones', $name);
  64. return 'Dr. ' . $name;
  65. }));
  66. $entity->set('name', 'Jones');
  67. $this->assertEquals('Dr. Jones', $entity->name);
  68. }
  69. /**
  70. * Tests setting multiple properties using a setter function
  71. *
  72. * @return void
  73. */
  74. public function testMultipleWithSetter() {
  75. $entity = $this->getMock('\Cake\ORM\Entity', ['_setName', '_setStuff']);
  76. $entity->accessible('*', true);
  77. $entity->expects($this->once())->method('_setName')
  78. ->with('Jones')
  79. ->will($this->returnCallback(function ($name) {
  80. $this->assertEquals('Jones', $name);
  81. return 'Dr. ' . $name;
  82. }));
  83. $entity->expects($this->once())->method('_setStuff')
  84. ->with(['a', 'b'])
  85. ->will($this->returnCallback(function ($stuff) {
  86. $this->assertEquals(['a', 'b'], $stuff);
  87. return ['c', 'd'];
  88. }));
  89. $entity->set(['name' => 'Jones', 'stuff' => ['a', 'b']]);
  90. $this->assertEquals('Dr. Jones', $entity->name);
  91. $this->assertEquals(['c', 'd'], $entity->stuff);
  92. }
  93. /**
  94. * Tests that it is possible to bypass the setters
  95. *
  96. * @return void
  97. */
  98. public function testBypassSetters() {
  99. $entity = $this->getMock('\Cake\ORM\Entity', ['_setName', '_setStuff']);
  100. $entity->accessible('*', true);
  101. $entity->expects($this->never())->method('_setName');
  102. $entity->expects($this->never())->method('_setStuff');
  103. $entity->set('name', 'Jones', ['setter' => false]);
  104. $this->assertEquals('Jones', $entity->name);
  105. $entity->set('stuff', 'Thing', ['setter' => false]);
  106. $this->assertEquals('Thing', $entity->stuff);
  107. $entity->set(['name' => 'foo', 'stuff' => 'bar'], ['setter' => false]);
  108. $this->assertEquals('bar', $entity->stuff);
  109. }
  110. /**
  111. * Tests that the constructor will set initial properties
  112. *
  113. * @return void
  114. */
  115. public function testConstructor() {
  116. $entity = $this->getMockBuilder('\Cake\ORM\Entity')
  117. ->setMethods(['set'])
  118. ->disableOriginalConstructor()
  119. ->getMock();
  120. $entity->expects($this->at(0))
  121. ->method('set')
  122. ->with(['a' => 'b', 'c' => 'd'], ['setter' => true, 'guard' => false]);
  123. $entity->expects($this->at(1))
  124. ->method('set')
  125. ->with(['foo' => 'bar'], ['setter' => false, 'guard' => false]);
  126. $entity->__construct(['a' => 'b', 'c' => 'd']);
  127. $entity->__construct(['foo' => 'bar'], ['useSetters' => false]);
  128. }
  129. /**
  130. * Tests that the constructor will set initial properties and pass the guard
  131. * option along
  132. *
  133. * @return void
  134. */
  135. public function testConstructorWithGuard() {
  136. $entity = $this->getMockBuilder('\Cake\ORM\Entity')
  137. ->setMethods(['set'])
  138. ->disableOriginalConstructor()
  139. ->getMock();
  140. $entity->expects($this->once())
  141. ->method('set')
  142. ->with(['foo' => 'bar'], ['setter' => true, 'guard' => true]);
  143. $entity->__construct(['foo' => 'bar'], ['guard' => true]);
  144. }
  145. /**
  146. * Tests getting properties with no custom getters
  147. *
  148. * @return void
  149. */
  150. public function testGetNoGetters() {
  151. $entity = new Entity(['id' => 1, 'foo' => 'bar']);
  152. $this->assertSame(1, $entity->get('id'));
  153. $this->assertSame('bar', $entity->get('foo'));
  154. }
  155. /**
  156. * Tests get with custom getter
  157. *
  158. * @return void
  159. */
  160. public function testGetCustomGetters() {
  161. $entity = $this->getMock('\Cake\ORM\Entity', ['_getName']);
  162. $entity->expects($this->exactly(2))->method('_getName')
  163. ->with('Jones')
  164. ->will($this->returnCallback(function ($name) {
  165. $this->assertSame('Jones', $name);
  166. return 'Dr. ' . $name;
  167. }));
  168. $entity->set('name', 'Jones');
  169. $this->assertEquals('Dr. Jones', $entity->get('name'));
  170. $this->assertEquals('Dr. Jones', $entity->get('name'));
  171. }
  172. /**
  173. * Test magic property setting with no custom setter
  174. *
  175. * @return void
  176. */
  177. public function testMagicSet() {
  178. $entity = new Entity;
  179. $entity->name = 'Jones';
  180. $this->assertEquals('Jones', $entity->name);
  181. $entity->name = 'George';
  182. $this->assertEquals('George', $entity->name);
  183. }
  184. /**
  185. * Tests magic set with custom setter function
  186. *
  187. * @return void
  188. */
  189. public function testMagicSetWithSetter() {
  190. $entity = $this->getMock('\Cake\ORM\Entity', ['_setName']);
  191. $entity->expects($this->once())->method('_setName')
  192. ->with('Jones')
  193. ->will($this->returnCallback(function ($name) {
  194. $this->assertEquals('Jones', $name);
  195. return 'Dr. ' . $name;
  196. }));
  197. $entity->name = 'Jones';
  198. $this->assertEquals('Dr. Jones', $entity->name);
  199. }
  200. /**
  201. * Tests the magic getter with a custom getter function
  202. *
  203. * @return void
  204. */
  205. public function testMagicGetWithGetter() {
  206. $entity = $this->getMock('\Cake\ORM\Entity', ['_getName']);
  207. $entity->expects($this->once())->method('_getName')
  208. ->with('Jones')
  209. ->will($this->returnCallback(function ($name) {
  210. $this->assertSame('Jones', $name);
  211. return 'Dr. ' . $name;
  212. }));
  213. $entity->set('name', 'Jones');
  214. $this->assertEquals('Dr. Jones', $entity->name);
  215. }
  216. /**
  217. * Test indirectly modifying internal properties
  218. *
  219. * @return void
  220. */
  221. public function testIndirectModification() {
  222. $entity = new Entity;
  223. $entity->things = ['a', 'b'];
  224. $entity->things[] = 'c';
  225. $this->assertEquals(['a', 'b', 'c'], $entity->things);
  226. }
  227. /**
  228. * Tests has() method
  229. *
  230. * @return void
  231. */
  232. public function testHas() {
  233. $entity = new Entity(['id' => 1, 'name' => 'Juan', 'foo' => null]);
  234. $this->assertTrue($entity->has('id'));
  235. $this->assertTrue($entity->has('name'));
  236. $this->assertFalse($entity->has('foo'));
  237. $this->assertFalse($entity->has('last_name'));
  238. $this->assertTrue($entity->has(['id']));
  239. $this->assertTrue($entity->has(['id', 'name']));
  240. $this->assertFalse($entity->has(['id', 'foo']));
  241. $this->assertFalse($entity->has(['id', 'nope']));
  242. $entity = $this->getMock('\Cake\ORM\Entity', ['_getThings']);
  243. $entity->expects($this->once())->method('_getThings')
  244. ->will($this->returnValue(0));
  245. $this->assertTrue($entity->has('things'));
  246. }
  247. /**
  248. * Tests unsetProperty one property at a time
  249. *
  250. * @return void
  251. */
  252. public function testUnset() {
  253. $entity = new Entity(['id' => 1, 'name' => 'bar']);
  254. $entity->unsetProperty('id');
  255. $this->assertFalse($entity->has('id'));
  256. $this->assertTrue($entity->has('name'));
  257. $entity->unsetProperty('name');
  258. $this->assertFalse($entity->has('id'));
  259. }
  260. /**
  261. * Unsetting a property should not mark it as dirty.
  262. *
  263. * @return void
  264. */
  265. public function testUnsetMakesClean() {
  266. $entity = new Entity(['id' => 1, 'name' => 'bar']);
  267. $this->assertTrue($entity->dirty('name'));
  268. $entity->unsetProperty('name');
  269. $this->assertFalse($entity->dirty('name'), 'Removed properties are not dirty.');
  270. }
  271. /**
  272. * Tests unsetProperty whith multiple properties
  273. *
  274. * @return void
  275. */
  276. public function testUnsetMultiple() {
  277. $entity = new Entity(['id' => 1, 'name' => 'bar', 'thing' => 2]);
  278. $entity->unsetProperty(['id', 'thing']);
  279. $this->assertFalse($entity->has('id'));
  280. $this->assertTrue($entity->has('name'));
  281. $this->assertFalse($entity->has('thing'));
  282. }
  283. /**
  284. * Tests the magic __isset() method
  285. *
  286. * @return void
  287. */
  288. public function testMagicIsset() {
  289. $entity = new Entity(['id' => 1, 'name' => 'Juan', 'foo' => null]);
  290. $this->assertTrue(isset($entity->id));
  291. $this->assertTrue(isset($entity->name));
  292. $this->assertFalse(isset($entity->foo));
  293. $this->assertFalse(isset($entity->thing));
  294. }
  295. /**
  296. * Tests the magic __unset() method
  297. *
  298. * @return void
  299. */
  300. public function testMagicUnset() {
  301. $entity = $this->getMock('\Cake\ORM\Entity', ['unsetProperty']);
  302. $entity->expects($this->at(0))
  303. ->method('unsetProperty')
  304. ->with('foo');
  305. unset($entity->foo);
  306. }
  307. /**
  308. * Tests isset with array access
  309. *
  310. * @return void
  311. */
  312. public function testIssetArrayAccess() {
  313. $entity = new Entity(['id' => 1, 'name' => 'Juan', 'foo' => null]);
  314. $this->assertTrue(isset($entity['id']));
  315. $this->assertTrue(isset($entity['name']));
  316. $this->assertFalse(isset($entity['foo']));
  317. $this->assertFalse(isset($entity['thing']));
  318. }
  319. /**
  320. * Tests get property with array access
  321. *
  322. * @return void
  323. */
  324. public function testGetArrayAccess() {
  325. $entity = $this->getMock('\Cake\ORM\Entity', ['get']);
  326. $entity->expects($this->at(0))
  327. ->method('get')
  328. ->with('foo')
  329. ->will($this->returnValue('worked'));
  330. $entity->expects($this->at(1))
  331. ->method('get')
  332. ->with('bar')
  333. ->will($this->returnValue('worked too'));
  334. $this->assertEquals('worked', $entity['foo']);
  335. $this->assertEquals('worked too', $entity['bar']);
  336. }
  337. /**
  338. * Tests set with array access
  339. *
  340. * @return void
  341. */
  342. public function testSetArrayAccess() {
  343. $entity = $this->getMock('\Cake\ORM\Entity', ['set']);
  344. $entity->accessible('*', true);
  345. $entity->expects($this->at(0))
  346. ->method('set')
  347. ->with('foo', 1)
  348. ->will($this->returnSelf());
  349. $entity->expects($this->at(1))
  350. ->method('set')
  351. ->with('bar', 2)
  352. ->will($this->returnSelf());
  353. $entity['foo'] = 1;
  354. $entity['bar'] = 2;
  355. }
  356. /**
  357. * Tests unset with array access
  358. *
  359. * @return void
  360. */
  361. public function testUnsetArrayAccess() {
  362. $entity = $this->getMock('\Cake\ORM\Entity', ['unsetProperty']);
  363. $entity->expects($this->at(0))
  364. ->method('unsetProperty')
  365. ->with('foo');
  366. unset($entity['foo']);
  367. }
  368. /**
  369. * Tests that the method cache will only report the methods for the called class,
  370. * this is, calling methods defined in another entity will not cause a fatal error
  371. * when trying to call directly an inexistent method in another class
  372. *
  373. * @return void
  374. */
  375. public function testMethodCache() {
  376. $entity = $this->getMock('\Cake\ORM\Entity', ['_setFoo', '_getBar']);
  377. $entity2 = $this->getMock('\Cake\ORM\Entity', ['_setBar']);
  378. $entity->expects($this->once())->method('_setFoo');
  379. $entity->expects($this->once())->method('_getBar');
  380. $entity2->expects($this->once())->method('_setBar');
  381. $entity->set('foo', 1);
  382. $entity->get('bar');
  383. $entity2->set('bar', 1);
  384. }
  385. /**
  386. * Tests that long properties in the entity are inflected correctly
  387. *
  388. * @return void
  389. */
  390. public function testSetGetLongProperyNames() {
  391. $entity = $this->getMock('\Cake\ORM\Entity', ['_getVeryLongProperty', '_setVeryLongProperty']);
  392. $entity->expects($this->once())->method('_getVeryLongProperty');
  393. $entity->expects($this->once())->method('_setVeryLongProperty');
  394. $entity->get('very_long_property');
  395. $entity->set('very_long_property', 1);
  396. }
  397. /**
  398. * Tests serializing an entity as json
  399. *
  400. * @return void
  401. */
  402. public function testJsonSerialize() {
  403. $data = ['name' => 'James', 'age' => 20, 'phones' => ['123', '457']];
  404. $entity = new Entity($data);
  405. $this->assertEquals(json_encode($data), json_encode($entity));
  406. }
  407. /**
  408. * Tests the extract method
  409. *
  410. * @return void
  411. */
  412. public function testExtract() {
  413. $entity = new Entity([
  414. 'id' => 1,
  415. 'title' => 'Foo',
  416. 'author_id' => 3
  417. ]);
  418. $expected = ['author_id' => 3, 'title' => 'Foo', ];
  419. $this->assertEquals($expected, $entity->extract(['author_id', 'title']));
  420. $expected = ['id' => 1];
  421. $this->assertEquals($expected, $entity->extract(['id']));
  422. $expected = [];
  423. $this->assertEquals($expected, $entity->extract([]));
  424. $expected = ['id' => 1, 'crazyness' => null];
  425. $this->assertEquals($expected, $entity->extract(['id', 'crazyness']));
  426. }
  427. /**
  428. * Tests dirty() method on a newly created object
  429. *
  430. * @return void
  431. */
  432. public function testDirty() {
  433. $entity = new Entity([
  434. 'id' => 1,
  435. 'title' => 'Foo',
  436. 'author_id' => 3
  437. ]);
  438. $this->assertTrue($entity->dirty('id'));
  439. $this->assertTrue($entity->dirty('title'));
  440. $this->assertTrue($entity->dirty('author_id'));
  441. $this->assertTrue($entity->dirty());
  442. $entity->dirty('id', false);
  443. $this->assertFalse($entity->dirty('id'));
  444. $this->assertTrue($entity->dirty('title'));
  445. $entity->dirty('title', false);
  446. $this->assertFalse($entity->dirty('title'));
  447. $this->assertTrue($entity->dirty());
  448. $entity->dirty('author_id', false);
  449. $this->assertFalse($entity->dirty());
  450. }
  451. /**
  452. * Tests dirty() when altering properties values and adding new ones
  453. *
  454. * @return void
  455. */
  456. public function testDirtyChangingProperties() {
  457. $entity = new Entity([
  458. 'title' => 'Foo',
  459. ]);
  460. $entity->dirty('title', false);
  461. $this->assertFalse($entity->dirty('title'));
  462. $entity->set('title', 'Foo');
  463. $this->assertTrue($entity->dirty('title'));
  464. $entity->set('title', 'Foo');
  465. $this->assertTrue($entity->dirty('title'));
  466. $entity->set('something', 'else');
  467. $this->assertTrue($entity->dirty('something'));
  468. }
  469. /**
  470. * Tests extract only dirty properties
  471. *
  472. * @return void
  473. */
  474. public function testExtractDirty() {
  475. $entity = new Entity([
  476. 'id' => 1,
  477. 'title' => 'Foo',
  478. 'author_id' => 3
  479. ]);
  480. $entity->dirty('id', false);
  481. $entity->dirty('title', false);
  482. $expected = ['author_id' => 3];
  483. $result = $entity->extract(['id', 'title', 'author_id'], true);
  484. $this->assertEquals($expected, $result);
  485. }
  486. /**
  487. * Tests the clean method
  488. *
  489. * @return void
  490. */
  491. public function testClean() {
  492. $entity = new Entity([
  493. 'id' => 1,
  494. 'title' => 'Foo',
  495. 'author_id' => 3
  496. ]);
  497. $this->assertTrue($entity->dirty('id'));
  498. $this->assertTrue($entity->dirty('title'));
  499. $this->assertTrue($entity->dirty('author_id'));
  500. $entity->clean();
  501. $this->assertFalse($entity->dirty('id'));
  502. $this->assertFalse($entity->dirty('title'));
  503. $this->assertFalse($entity->dirty('author_id'));
  504. }
  505. /**
  506. * Tests the isNew method
  507. *
  508. * @return void
  509. */
  510. public function testIsNew() {
  511. $entity = new Entity([
  512. 'id' => 1,
  513. 'title' => 'Foo',
  514. 'author_id' => 3
  515. ]);
  516. $this->assertTrue($entity->isNew());
  517. $entity->isNew(true);
  518. $this->assertTrue($entity->isNew());
  519. $entity->isNew('derpy');
  520. $this->assertTrue($entity->isNew());
  521. $entity->isNew(false);
  522. $this->assertFalse($entity->isNew());
  523. }
  524. /**
  525. * Tests the constructor when passing the markClean option
  526. *
  527. * @return void
  528. */
  529. public function testConstructorWithClean() {
  530. $entity = $this->getMockBuilder('\Cake\ORM\Entity')
  531. ->setMethods(['clean'])
  532. ->disableOriginalConstructor()
  533. ->getMock();
  534. $entity->expects($this->never())->method('clean');
  535. $entity->__construct(['a' => 'b', 'c' => 'd']);
  536. $entity = $this->getMockBuilder('\Cake\ORM\Entity')
  537. ->setMethods(['clean'])
  538. ->disableOriginalConstructor()
  539. ->getMock();
  540. $entity->expects($this->once())->method('clean');
  541. $entity->__construct(['a' => 'b', 'c' => 'd'], ['markClean' => true]);
  542. }
  543. /**
  544. * Tests the constructor when passing the markClean option
  545. *
  546. * @return void
  547. */
  548. public function testConstructorWithMarkNew() {
  549. $entity = $this->getMockBuilder('\Cake\ORM\Entity')
  550. ->setMethods(['isNew'])
  551. ->disableOriginalConstructor()
  552. ->getMock();
  553. $entity->expects($this->never())->method('clean');
  554. $entity->__construct(['a' => 'b', 'c' => 'd']);
  555. $entity = $this->getMockBuilder('\Cake\ORM\Entity')
  556. ->setMethods(['isNew'])
  557. ->disableOriginalConstructor()
  558. ->getMock();
  559. $entity->expects($this->once())->method('isNew');
  560. $entity->__construct(['a' => 'b', 'c' => 'd'], ['markNew' => true]);
  561. }
  562. /**
  563. * Test toArray method.
  564. *
  565. * @return void
  566. */
  567. public function testToArray() {
  568. $data = ['name' => 'James', 'age' => 20, 'phones' => ['123', '457']];
  569. $entity = new Entity($data);
  570. $this->assertEquals($data, $entity->toArray());
  571. }
  572. /**
  573. * Test toArray recursive.
  574. *
  575. * @return void
  576. */
  577. public function testToArrayRecursive() {
  578. $data = ['id' => 1, 'name' => 'James', 'age' => 20, 'phones' => ['123', '457']];
  579. $user = new Entity($data);
  580. $comments = [
  581. new Entity(['user_id' => 1, 'body' => 'Comment 1']),
  582. new Entity(['user_id' => 1, 'body' => 'Comment 2']),
  583. ];
  584. $user->comments = $comments;
  585. $user->profile = new Entity(['email' => 'mark@example.com']);
  586. $expected = [
  587. 'id' => 1,
  588. 'name' => 'James',
  589. 'age' => 20,
  590. 'phones' => ['123', '457'],
  591. 'profile' => ['email' => 'mark@example.com'],
  592. 'comments' => [
  593. ['user_id' => 1, 'body' => 'Comment 1'],
  594. ['user_id' => 1, 'body' => 'Comment 2'],
  595. ]
  596. ];
  597. $this->assertEquals($expected, $user->toArray());
  598. }
  599. /**
  600. * Test that get accessors are called when converting to arrays.
  601. *
  602. * @return void
  603. */
  604. public function testToArrayWithAccessor() {
  605. $entity = $this->getMock('\Cake\ORM\Entity', ['_getName']);
  606. $entity->accessible('*', true);
  607. $entity->set(['name' => 'Mark', 'email' => 'mark@example.com']);
  608. $entity->expects($this->any())
  609. ->method('_getName')
  610. ->will($this->returnValue('Jose'));
  611. $expected = ['name' => 'Jose', 'email' => 'mark@example.com'];
  612. $this->assertEquals($expected, $entity->toArray());
  613. }
  614. /**
  615. * Test that toArray respects hidden properties.
  616. *
  617. * @return void
  618. */
  619. public function testToArrayHiddenProperties() {
  620. $data = ['secret' => 'sauce', 'name' => 'mark', 'id' => 1];
  621. $entity = new Entity($data);
  622. $entity->hiddenProperties(['secret']);
  623. $this->assertEquals(['name' => 'mark', 'id' => 1], $entity->toArray());
  624. }
  625. /**
  626. * Test toArray includes 'virtual' properties.
  627. *
  628. * @return void
  629. */
  630. public function testToArrayVirtualProperties() {
  631. $entity = $this->getMock('\Cake\ORM\Entity', ['_getName']);
  632. $entity->accessible('*', true);
  633. $entity->expects($this->any())
  634. ->method('_getName')
  635. ->will($this->returnValue('Jose'));
  636. $entity->set(['email' => 'mark@example.com']);
  637. $entity->virtualProperties(['name']);
  638. $expected = ['name' => 'Jose', 'email' => 'mark@example.com'];
  639. $this->assertEquals($expected, $entity->toArray());
  640. $this->assertEquals(['name'], $entity->virtualProperties());
  641. $entity->hiddenProperties(['name']);
  642. $expected = ['email' => 'mark@example.com'];
  643. $this->assertEquals($expected, $entity->toArray());
  644. $this->assertEquals(['name'], $entity->hiddenProperties());
  645. }
  646. /**
  647. * Tests that missing fields will not be passed as null to the validator
  648. *
  649. * @return void
  650. */
  651. public function testValidateMissingFields() {
  652. $entity = $this->getMockBuilder('\Cake\ORM\Entity')
  653. ->setMethods(['getSomething'])
  654. ->disableOriginalConstructor()
  655. ->getMock();
  656. $entity->accessible('*', true);
  657. $validator = $this->getMock('\Cake\Validation\Validator');
  658. $entity->set('a', 'b');
  659. $validator->expects($this->once())
  660. ->method('provider')
  661. ->with('entity', $entity);
  662. $validator->expects($this->once())->method('errors')
  663. ->with(['a' => 'b'], true)
  664. ->will($this->returnValue(['a' => ['not valid']]));
  665. $this->assertFalse($entity->validate($validator));
  666. $this->assertEquals(['a' => ['not valid']], $entity->errors());
  667. }
  668. /**
  669. * Tests validate when the validator returns no errors
  670. *
  671. * @return void
  672. */
  673. public function testValidateSuccess() {
  674. $validator = $this->getMock('\Cake\Validation\Validator');
  675. $data = [
  676. 'a' => 'b',
  677. 'cool' => false,
  678. 'something' => true
  679. ];
  680. $entity = new Entity($data);
  681. $entity->isNew(true);
  682. $validator->expects($this->once())
  683. ->method('provider')
  684. ->with('entity', $entity);
  685. $validator->expects($this->once())->method('errors')
  686. ->with($data, true)
  687. ->will($this->returnValue([]));
  688. $this->assertTrue($entity->validate($validator));
  689. $this->assertEquals([], $entity->errors());
  690. }
  691. /**
  692. * Tests the errors method
  693. *
  694. * @return void
  695. */
  696. public function testErrors() {
  697. $entity = new Entity;
  698. $this->assertEmpty($entity->errors());
  699. $this->assertSame($entity, $entity->errors('foo', 'bar'));
  700. $this->assertEquals(['bar'], $entity->errors('foo'));
  701. $this->assertEquals([], $entity->errors('boo'));
  702. $entity['boo'] = [
  703. 'someting' => 'stupid',
  704. 'and' => false
  705. ];
  706. $this->assertEquals([], $entity->errors('boo'));
  707. $entity->errors('foo', 'other error');
  708. $this->assertEquals(['other error'], $entity->errors('foo'));
  709. $entity->errors('bar', ['something', 'bad']);
  710. $this->assertEquals(['something', 'bad'], $entity->errors('bar'));
  711. $expected = ['foo' => ['other error'], 'bar' => ['something', 'bad']];
  712. $this->assertEquals($expected, $entity->errors());
  713. $errors = ['foo' => ['something'], 'bar' => 'else', 'baz' => ['error']];
  714. $this->assertSame($entity, $entity->errors($errors));
  715. $errors['bar'] = ['else'];
  716. $this->assertEquals($errors, $entity->errors());
  717. }
  718. /**
  719. * Tests that it is possible to get errors for nested entities
  720. *
  721. * @return void
  722. */
  723. public function testErrorsDeep() {
  724. $entity2 = new Entity;
  725. $entity3 = new Entity;
  726. $entity = new Entity([
  727. 'foo' => 'bar',
  728. 'thing' => 'baz',
  729. 'user' => $entity2,
  730. 'owner' => $entity3
  731. ]);
  732. $entity->errors('thing', ['this is a mistake']);
  733. $entity2->errors(['a' => ['error1'], 'b' => ['error2']]);
  734. $entity3->errors(['c' => ['error3'], 'd' => ['error4']]);
  735. $expected = ['a' => ['error1'], 'b' => ['error2']];
  736. $this->assertEquals($expected, $entity->errors('user'));
  737. $expected = ['c' => ['error3'], 'd' => ['error4']];
  738. $this->assertEquals($expected, $entity->errors('owner'));
  739. $entity->set('multiple', [$entity2, $entity3]);
  740. $expected = [
  741. ['a' => ['error1'], 'b' => ['error2']],
  742. ['c' => ['error3'], 'd' => ['error4']]
  743. ];
  744. $this->assertEquals($expected, $entity->errors('multiple'));
  745. }
  746. /**
  747. * Test that errors can be read with a path.
  748. *
  749. * @return void
  750. */
  751. public function testErrorPathReading() {
  752. $assoc = new Entity;
  753. $entity = new Entity([
  754. 'field' => 'value',
  755. 'one' => $assoc,
  756. 'many' => [$assoc]
  757. ]);
  758. $entity->errors('wrong', 'Bad stuff');
  759. $assoc->errors('nope', 'Terrible things');
  760. $this->assertEquals(['Bad stuff'], $entity->errors('wrong'));
  761. $this->assertEquals(['Terrible things'], $entity->errors('many.0.nope'));
  762. $this->assertEquals(['Terrible things'], $entity->errors('one.nope'));
  763. $this->assertEquals(['nope' => ['Terrible things']], $entity->errors('one'));
  764. $this->assertEquals([0 => ['nope' => ['Terrible things']]], $entity->errors('many'));
  765. $this->assertEquals(['nope' => ['Terrible things']], $entity->errors('many.0'));
  766. $this->assertEquals([], $entity->errors('many.0.mistake'));
  767. $this->assertEquals([], $entity->errors('one.mistake'));
  768. $this->assertEquals([], $entity->errors('one.1.mistake'));
  769. $this->assertEquals([], $entity->errors('many.1.nope'));
  770. }
  771. /**
  772. * Tests that changing the value of a property will remove errors
  773. * stored for it
  774. *
  775. * @return void
  776. */
  777. public function testDirtyRemovesError() {
  778. $entity = new Entity(['a' => 'b']);
  779. $entity->errors('a', 'is not good');
  780. $entity->set('a', 'c');
  781. $this->assertEmpty($entity->errors('a'));
  782. $entity->errors('a', 'is not good');
  783. $entity->dirty('a', true);
  784. $this->assertEmpty($entity->errors('a'));
  785. }
  786. /**
  787. * Tests that marking an entity as clean will remove errors too
  788. *
  789. * @return void
  790. */
  791. public function testCleanRemovesErrors() {
  792. $entity = new Entity(['a' => 'b']);
  793. $entity->errors('a', 'is not good');
  794. $entity->clean();
  795. $this->assertEmpty($entity->errors());
  796. }
  797. /**
  798. * Tests accessible() method as a getter and setter
  799. *
  800. * @return void
  801. */
  802. public function testAccessible() {
  803. $entity = new Entity;
  804. $entity->accessible('*', false);
  805. $this->assertFalse($entity->accessible('foo'));
  806. $this->assertFalse($entity->accessible('bar'));
  807. $this->assertSame($entity, $entity->accessible('foo', true));
  808. $this->assertTrue($entity->accessible('foo'));
  809. $this->assertFalse($entity->accessible('bar'));
  810. $this->assertSame($entity, $entity->accessible('bar', true));
  811. $this->assertTrue($entity->accessible('foo'));
  812. $this->assertTrue($entity->accessible('bar'));
  813. $this->assertSame($entity, $entity->accessible('foo', false));
  814. $this->assertFalse($entity->accessible('foo'));
  815. $this->assertTrue($entity->accessible('bar'));
  816. $this->assertSame($entity, $entity->accessible('bar', false));
  817. $this->assertFalse($entity->accessible('foo'));
  818. $this->assertFalse($entity->accessible('bar'));
  819. }
  820. /**
  821. * Tests that an array can be used to set
  822. *
  823. * @return void
  824. */
  825. public function testAccessibleAsArray() {
  826. $entity = new Entity;
  827. $entity->accessible(['foo', 'bar', 'baz'], true);
  828. $this->assertTrue($entity->accessible('foo'));
  829. $this->assertTrue($entity->accessible('bar'));
  830. $this->assertTrue($entity->accessible('baz'));
  831. $entity->accessible('foo', false);
  832. $this->assertFalse($entity->accessible('foo'));
  833. $this->assertTrue($entity->accessible('bar'));
  834. $this->assertTrue($entity->accessible('baz'));
  835. $entity->accessible(['foo', 'bar', 'baz'], false);
  836. $this->assertFalse($entity->accessible('foo'));
  837. $this->assertFalse($entity->accessible('bar'));
  838. $this->assertFalse($entity->accessible('baz'));
  839. }
  840. /**
  841. * Tests that a wildcard can be used for setting accesible properties
  842. *
  843. * @return void
  844. */
  845. public function testAccessibleWildcard() {
  846. $entity = new Entity;
  847. $entity->accessible(['foo', 'bar', 'baz'], true);
  848. $this->assertTrue($entity->accessible('foo'));
  849. $this->assertTrue($entity->accessible('bar'));
  850. $this->assertTrue($entity->accessible('baz'));
  851. $entity->accessible('*', false);
  852. $this->assertFalse($entity->accessible('foo'));
  853. $this->assertFalse($entity->accessible('bar'));
  854. $this->assertFalse($entity->accessible('baz'));
  855. $this->assertFalse($entity->accessible('newOne'));
  856. $entity->accessible('*', true);
  857. $this->assertTrue($entity->accessible('foo'));
  858. $this->assertTrue($entity->accessible('bar'));
  859. $this->assertTrue($entity->accessible('baz'));
  860. $this->assertTrue($entity->accessible('newOne2'));
  861. }
  862. /**
  863. * Tests that only accessible properties can be set
  864. *
  865. * @return void
  866. */
  867. public function testSetWithAccessible() {
  868. $entity = new Entity(['foo' => 1, 'bar' => 2]);
  869. $options = ['guard' => true];
  870. $entity->accessible('*', false);
  871. $entity->accessible('foo', true);
  872. $entity->set('bar', 3, $options);
  873. $entity->set('foo', 4, $options);
  874. $this->assertEquals(2, $entity->get('bar'));
  875. $this->assertEquals(4, $entity->get('foo'));
  876. $entity->accessible('bar', true);
  877. $entity->set('bar', 3, $options);
  878. $this->assertEquals(3, $entity->get('bar'));
  879. }
  880. /**
  881. * Tests that only accessible properties can be set
  882. *
  883. * @return void
  884. */
  885. public function testSetWithAccessibleWithArray() {
  886. $entity = new Entity(['foo' => 1, 'bar' => 2]);
  887. $options = ['guard' => true];
  888. $entity->accessible('*', false);
  889. $entity->accessible('foo', true);
  890. $entity->set(['bar' => 3, 'foo' => 4], $options);
  891. $this->assertEquals(2, $entity->get('bar'));
  892. $this->assertEquals(4, $entity->get('foo'));
  893. $entity->accessible('bar', true);
  894. $entity->set(['bar' => 3, 'foo' => 5], $options);
  895. $this->assertEquals(3, $entity->get('bar'));
  896. $this->assertEquals(5, $entity->get('foo'));
  897. }
  898. /**
  899. * Test that accessible() and single property setting works.
  900. *
  901. * @return void
  902. */
  903. public function testSetWithAccessibleSingleProperty() {
  904. $entity = new Entity(['foo' => 1, 'bar' => 2]);
  905. $entity->accessible('*', false);
  906. $entity->accessible('title', true);
  907. $entity->set(['title' => 'test', 'body' => 'Nope']);
  908. $this->assertEquals('test', $entity->title);
  909. $this->assertNull($entity->body);
  910. $entity->body = 'Yep';
  911. $this->assertEquals('Yep', $entity->body, 'Single set should bypass guards.');
  912. $entity->set('body', 'Yes');
  913. $this->assertEquals('Yes', $entity->body, 'Single set should bypass guards.');
  914. }
  915. /**
  916. * Tests the entity's __toString method
  917. *
  918. * @return void
  919. */
  920. public function testToString() {
  921. $entity = new Entity(['foo' => 1, 'bar' => 2]);
  922. $this->assertEquals(json_encode($entity, JSON_PRETTY_PRINT), (string)$entity);
  923. }
  924. /**
  925. * Tests __debugInfo
  926. *
  927. * @return void
  928. */
  929. public function testDebugInfo() {
  930. $entity = new Entity(['foo' => 'bar'], ['markClean' => true]);
  931. $entity->accessible('name', true);
  932. $entity->virtualProperties(['baz']);
  933. $entity->dirty('foo', true);
  934. $entity->errors('foo', ['An error']);
  935. $entity->source('foos');
  936. $result = $entity->__debugInfo();
  937. $expected = [
  938. 'new' => true,
  939. 'accessible' => ['*' => true, 'name' => true],
  940. 'properties' => ['foo' => 'bar'],
  941. 'dirty' => ['foo' => true],
  942. 'virtual' => ['baz'],
  943. 'errors' => ['foo' => ['An error']],
  944. 'repository' => 'foos'
  945. ];
  946. $this->assertSame($expected, $result);
  947. }
  948. /**
  949. * Tests the source method
  950. *
  951. * @return void
  952. */
  953. public function testSource() {
  954. $entity = new Entity;
  955. $this->assertNull($entity->source());
  956. $entity->source('foos');
  957. $this->assertEquals('foos', $entity->source());
  958. }
  959. /**
  960. * Provides empty values
  961. *
  962. * @return void
  963. */
  964. public function emptyNamesProvider() {
  965. return [[''], [null], [false]];
  966. }
  967. /**
  968. * Tests that trying to get an empty propery name throws exception
  969. *
  970. * @dataProvider emptyNamesProvider
  971. * @expectedException \InvalidArgumentException
  972. * @return void
  973. */
  974. public function testEmptyProperties($property) {
  975. $entity = new Entity();
  976. $entity->get($property);
  977. }
  978. /**
  979. * Tests that setitng an empty property name does nothing
  980. *
  981. * @expectedException \InvalidArgumentException
  982. * @dataProvider emptyNamesProvider
  983. * @return void
  984. */
  985. public function testSetEmptyPropertyName($property) {
  986. $entity = new Entity();
  987. $entity->set($property, 'bar');
  988. }
  989. }