EntityTest.php 30 KB

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