RulesCheckerIntegrationTest.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  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\RulesChecker;
  18. use Cake\ORM\TableRegistry;
  19. use Cake\TestSuite\TestCase;
  20. /**
  21. * Tests the integration between the ORM and the domain checker
  22. */
  23. class RulesCheckerIntegrationTest extends TestCase
  24. {
  25. /**
  26. * Fixtures to be loaded
  27. *
  28. * @var array
  29. */
  30. public $fixtures = ['core.articles', 'core.articles_tags', 'core.authors', 'core.tags'];
  31. /**
  32. * Tear down
  33. *
  34. * @return void
  35. */
  36. public function tearDown()
  37. {
  38. parent::tearDown();
  39. TableRegistry::clear();
  40. }
  41. /**
  42. * Tests saving belongsTo association and get a validation error
  43. *
  44. * @group save
  45. * @return void
  46. */
  47. public function testsSaveBelongsToWithValidationError()
  48. {
  49. $entity = new Entity([
  50. 'title' => 'A Title',
  51. 'body' => 'A body'
  52. ]);
  53. $entity->author = new Entity([
  54. 'name' => 'Jose'
  55. ]);
  56. $table = TableRegistry::get('articles');
  57. $table->belongsTo('authors');
  58. $table->association('authors')
  59. ->target()
  60. ->rulesChecker()
  61. ->add(
  62. function (Entity $author, array $options) use ($table) {
  63. $this->assertSame($options['repository'], $table->association('authors')->target());
  64. return false;
  65. },
  66. ['errorField' => 'name', 'message' => 'This is an error']
  67. );
  68. $this->assertFalse($table->save($entity));
  69. $this->assertTrue($entity->isNew());
  70. $this->assertTrue($entity->author->isNew());
  71. $this->assertNull($entity->get('author_id'));
  72. $this->assertNotEmpty($entity->author->errors('name'));
  73. $this->assertEquals(['This is an error'], $entity->author->errors('name'));
  74. }
  75. /**
  76. * Tests saving hasOne association and returning a validation error will
  77. * abort the saving process
  78. *
  79. * @group save
  80. * @return void
  81. */
  82. public function testSaveHasOneWithValidationError()
  83. {
  84. $entity = new \Cake\ORM\Entity([
  85. 'name' => 'Jose'
  86. ]);
  87. $entity->article = new \Cake\ORM\Entity([
  88. 'title' => 'A Title',
  89. 'body' => 'A body'
  90. ]);
  91. $table = TableRegistry::get('authors');
  92. $table->hasOne('articles');
  93. $table->association('articles')
  94. ->target()
  95. ->rulesChecker()
  96. ->add(
  97. function (Entity $entity) {
  98. return false;
  99. },
  100. ['errorField' => 'title', 'message' => 'This is an error']
  101. );
  102. $this->assertFalse($table->save($entity));
  103. $this->assertTrue($entity->isNew());
  104. $this->assertTrue($entity->article->isNew());
  105. $this->assertNull($entity->article->id);
  106. $this->assertNull($entity->article->get('author_id'));
  107. $this->assertFalse($entity->article->dirty('author_id'));
  108. $this->assertNotEmpty($entity->article->errors('title'));
  109. }
  110. /**
  111. * Tests saving multiple entities in a hasMany association and getting and
  112. * error while saving one of them. It should abort all the save operation
  113. * when options are set to defaults
  114. *
  115. * @return void
  116. */
  117. public function testSaveHasManyWithErrorsAtomic()
  118. {
  119. $entity = new \Cake\ORM\Entity([
  120. 'name' => 'Jose'
  121. ]);
  122. $entity->articles = [
  123. new \Cake\ORM\Entity([
  124. 'title' => '1',
  125. 'body' => 'A body'
  126. ]),
  127. new \Cake\ORM\Entity([
  128. 'title' => 'Another Title',
  129. 'body' => 'Another body'
  130. ])
  131. ];
  132. $table = TableRegistry::get('authors');
  133. $table->hasMany('articles');
  134. $table->association('articles')
  135. ->target()
  136. ->rulesChecker()
  137. ->add(
  138. function (Entity $entity, $options) use ($table) {
  139. $this->assertSame($table, $options['_sourceTable']);
  140. return $entity->title === '1';
  141. },
  142. ['errorField' => 'title', 'message' => 'This is an error']
  143. );
  144. $this->assertFalse($table->save($entity));
  145. $this->assertTrue($entity->isNew());
  146. $this->assertTrue($entity->articles[0]->isNew());
  147. $this->assertTrue($entity->articles[1]->isNew());
  148. $this->assertNull($entity->articles[0]->id);
  149. $this->assertNull($entity->articles[1]->id);
  150. $this->assertNull($entity->articles[0]->author_id);
  151. $this->assertNull($entity->articles[1]->author_id);
  152. $this->assertEmpty($entity->articles[0]->errors());
  153. $this->assertNotEmpty($entity->articles[1]->errors());
  154. }
  155. /**
  156. * Tests that it is possible to continue saving hasMany associations
  157. * even if any of the records fail validation when atomic is set
  158. * to false
  159. *
  160. * @return void
  161. */
  162. public function testSaveHasManyWithErrorsNonAtomic()
  163. {
  164. $entity = new \Cake\ORM\Entity([
  165. 'name' => 'Jose'
  166. ]);
  167. $entity->articles = [
  168. new \Cake\ORM\Entity([
  169. 'title' => 'A title',
  170. 'body' => 'A body'
  171. ]),
  172. new \Cake\ORM\Entity([
  173. 'title' => '1',
  174. 'body' => 'Another body'
  175. ])
  176. ];
  177. $table = TableRegistry::get('authors');
  178. $table->hasMany('articles');
  179. $table->association('articles')
  180. ->target()
  181. ->rulesChecker()
  182. ->add(
  183. function (Entity $article) {
  184. return is_numeric($article->title);
  185. },
  186. ['errorField' => 'title', 'message' => 'This is an error']
  187. );
  188. $result = $table->save($entity, ['atomic' => false]);
  189. $this->assertSame($entity, $result);
  190. $this->assertFalse($entity->isNew());
  191. $this->assertTrue($entity->articles[0]->isNew());
  192. $this->assertFalse($entity->articles[1]->isNew());
  193. $this->assertEquals(4, $entity->articles[1]->id);
  194. $this->assertNull($entity->articles[0]->id);
  195. $this->assertNotEmpty($entity->articles[0]->errors('title'));
  196. }
  197. /**
  198. * Tests saving belongsToMany records with a validation error in a joint entity
  199. *
  200. * @group save
  201. * @return void
  202. */
  203. public function testSaveBelongsToManyWithValidationErrorInJointEntity()
  204. {
  205. $entity = new \Cake\ORM\Entity([
  206. 'title' => 'A Title',
  207. 'body' => 'A body'
  208. ]);
  209. $entity->tags = [
  210. new \Cake\ORM\Entity([
  211. 'name' => 'Something New'
  212. ]),
  213. new \Cake\ORM\Entity([
  214. 'name' => '100'
  215. ])
  216. ];
  217. $table = TableRegistry::get('articles');
  218. $table->belongsToMany('tags');
  219. $table->association('tags')
  220. ->junction()
  221. ->rulesChecker()
  222. ->add(function (Entity $entity) {
  223. return $entity->article_id > 4;
  224. });
  225. $this->assertFalse($table->save($entity));
  226. $this->assertTrue($entity->isNew());
  227. $this->assertTrue($entity->tags[0]->isNew());
  228. $this->assertTrue($entity->tags[1]->isNew());
  229. $this->assertNull($entity->tags[0]->id);
  230. $this->assertNull($entity->tags[1]->id);
  231. $this->assertNull($entity->tags[0]->_joinData);
  232. $this->assertNull($entity->tags[1]->_joinData);
  233. }
  234. /**
  235. * Tests saving belongsToMany records with a validation error in a joint entity
  236. * and atomic set to false
  237. *
  238. * @group save
  239. * @return void
  240. */
  241. public function testSaveBelongsToManyWithValidationErrorInJointEntityNonAtomic()
  242. {
  243. $entity = new \Cake\ORM\Entity([
  244. 'title' => 'A Title',
  245. 'body' => 'A body'
  246. ]);
  247. $entity->tags = [
  248. new \Cake\ORM\Entity([
  249. 'name' => 'Something New'
  250. ]),
  251. new \Cake\ORM\Entity([
  252. 'name' => 'New one'
  253. ])
  254. ];
  255. $table = TableRegistry::get('articles');
  256. $table->belongsToMany('tags');
  257. $table->association('tags')
  258. ->junction()
  259. ->rulesChecker()
  260. ->add(function (Entity $entity) {
  261. return $entity->tag_id > 4;
  262. });
  263. $this->assertSame($entity, $table->save($entity, ['atomic' => false]));
  264. $this->assertFalse($entity->isNew());
  265. $this->assertFalse($entity->tags[0]->isNew());
  266. $this->assertFalse($entity->tags[1]->isNew());
  267. $this->assertEquals(4, $entity->tags[0]->id);
  268. $this->assertEquals(5, $entity->tags[1]->id);
  269. $this->assertTrue($entity->tags[0]->_joinData->isNew());
  270. $this->assertEquals(4, $entity->tags[1]->_joinData->article_id);
  271. $this->assertEquals(5, $entity->tags[1]->_joinData->tag_id);
  272. }
  273. /**
  274. * Test adding rule with name
  275. *
  276. * @group save
  277. * @return void
  278. */
  279. public function testAddingRuleWithName()
  280. {
  281. $entity = new Entity([
  282. 'name' => 'larry'
  283. ]);
  284. $table = TableRegistry::get('Authors');
  285. $rules = $table->rulesChecker();
  286. $rules->add(
  287. function () {
  288. return false;
  289. },
  290. 'ruleName',
  291. ['errorField' => 'name']
  292. );
  293. $this->assertFalse($table->save($entity));
  294. $this->assertEquals(['ruleName' => 'invalid'], $entity->errors('name'));
  295. }
  296. /**
  297. * Tests the isUnique domain rule
  298. *
  299. * @group save
  300. * @return void
  301. */
  302. public function testIsUniqueDomainRule()
  303. {
  304. $entity = new Entity([
  305. 'name' => 'larry'
  306. ]);
  307. $table = TableRegistry::get('Authors');
  308. $rules = $table->rulesChecker();
  309. $rules->add($rules->isUnique(['name']));
  310. $this->assertFalse($table->save($entity));
  311. $this->assertEquals(['_isUnique' => 'This value is already in use'], $entity->errors('name'));
  312. $entity->name = 'jose';
  313. $this->assertSame($entity, $table->save($entity));
  314. $entity = $table->get(1);
  315. $entity->dirty('name', true);
  316. $this->assertSame($entity, $table->save($entity));
  317. }
  318. /**
  319. * Tests isUnique with multiple fields
  320. *
  321. * @group save
  322. * @return void
  323. */
  324. public function testIsUniqueMultipleFields()
  325. {
  326. $entity = new Entity([
  327. 'author_id' => 1,
  328. 'title' => 'First Article'
  329. ]);
  330. $table = TableRegistry::get('Articles');
  331. $rules = $table->rulesChecker();
  332. $rules->add($rules->isUnique(['title', 'author_id'], 'Nope'));
  333. $this->assertFalse($table->save($entity));
  334. $this->assertEquals(['title' => ['_isUnique' => 'Nope']], $entity->errors());
  335. $entity->clean();
  336. $entity->author_id = 2;
  337. $this->assertSame($entity, $table->save($entity));
  338. }
  339. /**
  340. * Tests the existsIn domain rule
  341. *
  342. * @group save
  343. * @return void
  344. */
  345. public function testExistsInDomainRule()
  346. {
  347. $entity = new Entity([
  348. 'title' => 'An Article',
  349. 'author_id' => 500
  350. ]);
  351. $table = TableRegistry::get('Articles');
  352. $table->belongsTo('Authors');
  353. $rules = $table->rulesChecker();
  354. $rules->add($rules->existsIn('author_id', 'Authors'));
  355. $this->assertFalse($table->save($entity));
  356. $this->assertEquals(['_existsIn' => 'This value does not exist'], $entity->errors('author_id'));
  357. }
  358. /**
  359. * Tests the existsIn domain rule when passing an object
  360. *
  361. * @group save
  362. * @return void
  363. */
  364. public function testExistsInDomainRuleWithObject()
  365. {
  366. $entity = new Entity([
  367. 'title' => 'An Article',
  368. 'author_id' => 500
  369. ]);
  370. $table = TableRegistry::get('Articles');
  371. $rules = $table->rulesChecker();
  372. $rules->add($rules->existsIn('author_id', TableRegistry::get('Authors'), 'Nope'));
  373. $this->assertFalse($table->save($entity));
  374. $this->assertEquals(['_existsIn' => 'Nope'], $entity->errors('author_id'));
  375. }
  376. /**
  377. * ExistsIn uses the schema to verify that nullable fields are ok.
  378. *
  379. * @return
  380. */
  381. public function testExistsInNullValue()
  382. {
  383. $entity = new Entity([
  384. 'title' => 'An Article',
  385. 'author_id' => null
  386. ]);
  387. $table = TableRegistry::get('Articles');
  388. $table->belongsTo('Authors');
  389. $rules = $table->rulesChecker();
  390. $rules->add($rules->existsIn('author_id', 'Authors'));
  391. $this->assertEquals($entity, $table->save($entity));
  392. $this->assertEquals([], $entity->errors('author_id'));
  393. }
  394. /**
  395. * Tests exists in uses the bindingKey of the association
  396. *
  397. * @return
  398. */
  399. public function testExistsInWithBindingKey()
  400. {
  401. $entity = new Entity([
  402. 'title' => 'An Article',
  403. ]);
  404. $table = TableRegistry::get('Articles');
  405. $table->belongsTo('Authors', [
  406. 'bindingKey' => 'name',
  407. 'foreignKey' => 'title'
  408. ]);
  409. $rules = $table->rulesChecker();
  410. $rules->add($rules->existsIn('title', 'Authors'));
  411. $this->assertFalse($table->save($entity));
  412. $this->assertNotEmpty($entity->errors('title'));
  413. $entity->clean();
  414. $entity->title = 'larry';
  415. $this->assertEquals($entity, $table->save($entity));
  416. }
  417. /**
  418. * Tests existsIn with invalid associations
  419. *
  420. * @group save
  421. * @expectedException RuntimeException
  422. * @expectedExceptionMessage ExistsIn rule for 'author_id' is invalid. The 'NotValid' association is not defined.
  423. * @return void
  424. */
  425. public function testExistsInInvalidAssociation()
  426. {
  427. $entity = new Entity([
  428. 'title' => 'An Article',
  429. 'author_id' => 500
  430. ]);
  431. $table = TableRegistry::get('Articles');
  432. $table->belongsTo('Authors');
  433. $rules = $table->rulesChecker();
  434. $rules->add($rules->existsIn('author_id', 'NotValid'));
  435. $table->save($entity);
  436. }
  437. /**
  438. * Tests the checkRules save option
  439. *
  440. * @group save
  441. * @return void
  442. */
  443. public function testSkipRulesChecking()
  444. {
  445. $entity = new Entity([
  446. 'title' => 'An Article',
  447. 'author_id' => 500
  448. ]);
  449. $table = TableRegistry::get('Articles');
  450. $rules = $table->rulesChecker();
  451. $rules->add($rules->existsIn('author_id', TableRegistry::get('Authors'), 'Nope'));
  452. $this->assertSame($entity, $table->save($entity, ['checkRules' => false]));
  453. }
  454. /**
  455. * Tests the beforeRules event
  456. *
  457. * @group save
  458. * @return void
  459. */
  460. public function testUseBeforeRules()
  461. {
  462. $entity = new Entity([
  463. 'title' => 'An Article',
  464. 'author_id' => 500
  465. ]);
  466. $table = TableRegistry::get('Articles');
  467. $rules = $table->rulesChecker();
  468. $rules->add($rules->existsIn('author_id', TableRegistry::get('Authors'), 'Nope'));
  469. $table->eventManager()->attach(
  470. function ($event, Entity $entity, \ArrayObject $options, $operation) {
  471. $this->assertEquals(
  472. [
  473. 'atomic' => true,
  474. 'associated' => true,
  475. 'checkRules' => true,
  476. 'checkExisting' => true,
  477. '_primary' => true,
  478. ],
  479. $options->getArrayCopy()
  480. );
  481. $this->assertEquals('create', $operation);
  482. $event->stopPropagation();
  483. return true;
  484. },
  485. 'Model.beforeRules'
  486. );
  487. $this->assertSame($entity, $table->save($entity));
  488. }
  489. /**
  490. * Tests the afterRules event
  491. *
  492. * @group save
  493. * @return void
  494. */
  495. public function testUseAfterRules()
  496. {
  497. $entity = new Entity([
  498. 'title' => 'An Article',
  499. 'author_id' => 500
  500. ]);
  501. $table = TableRegistry::get('Articles');
  502. $rules = $table->rulesChecker();
  503. $rules->add($rules->existsIn('author_id', TableRegistry::get('Authors'), 'Nope'));
  504. $table->eventManager()->attach(
  505. function ($event, Entity $entity, \ArrayObject $options, $result, $operation) {
  506. $this->assertEquals(
  507. [
  508. 'atomic' => true,
  509. 'associated' => true,
  510. 'checkRules' => true,
  511. 'checkExisting' => true,
  512. '_primary' => true,
  513. ],
  514. $options->getArrayCopy()
  515. );
  516. $this->assertEquals('create', $operation);
  517. $this->assertFalse($result);
  518. $event->stopPropagation();
  519. return true;
  520. },
  521. 'Model.afterRules'
  522. );
  523. $this->assertSame($entity, $table->save($entity));
  524. }
  525. /**
  526. * Tests that rules can be changed using the buildRules event
  527. *
  528. * @group save
  529. * @return void
  530. */
  531. public function testUseBuildRulesEvent()
  532. {
  533. $entity = new Entity([
  534. 'title' => 'An Article',
  535. 'author_id' => 500
  536. ]);
  537. $table = TableRegistry::get('Articles');
  538. $table->eventManager()->attach(function ($event, $rules) {
  539. $rules->add($rules->existsIn('author_id', TableRegistry::get('Authors'), 'Nope'));
  540. }, 'Model.buildRules');
  541. $this->assertFalse($table->save($entity));
  542. }
  543. /**
  544. * Tests isUnique with untouched fields
  545. *
  546. * @group save
  547. * @return void
  548. */
  549. public function testIsUniqueWithCleanFields()
  550. {
  551. $table = TableRegistry::get('Articles');
  552. $entity = $table->get(1);
  553. $rules = $table->rulesChecker();
  554. $rules->add($rules->isUnique(['title', 'author_id'], 'Nope'));
  555. $entity->body = 'Foo';
  556. $this->assertSame($entity, $table->save($entity));
  557. $entity->title = 'Third Article';
  558. $this->assertFalse($table->save($entity));
  559. }
  560. /**
  561. * Tests isUnique rule with coflicting columns
  562. *
  563. * @group save
  564. * @return void
  565. */
  566. public function testIsUniqueAliasPrefix()
  567. {
  568. $entity = new Entity([
  569. 'title' => 'An Article',
  570. 'author_id' => 1
  571. ]);
  572. $table = TableRegistry::get('Articles');
  573. $table->belongsTo('Authors');
  574. $rules = $table->rulesChecker();
  575. $rules->add($rules->isUnique(['author_id']));
  576. $table->Authors->eventManager()->on('Model.beforeFind', function ($event, $query) {
  577. $query->leftJoin(['a2' => 'authors']);
  578. });
  579. $this->assertFalse($table->save($entity));
  580. $this->assertEquals(['_isUnique' => 'This value is already in use'], $entity->errors('author_id'));
  581. }
  582. /**
  583. * Tests the existsIn rule when passing non dirty fields
  584. *
  585. * @group save
  586. * @return void
  587. */
  588. public function testExistsInWithCleanFields()
  589. {
  590. $table = TableRegistry::get('Articles');
  591. $table->belongsTo('Authors');
  592. $rules = $table->rulesChecker();
  593. $rules->add($rules->existsIn('author_id', 'Authors'));
  594. $entity = $table->get(1);
  595. $entity->title = 'Foo';
  596. $entity->author_id = 1000;
  597. $entity->dirty('author_id', false);
  598. $this->assertSame($entity, $table->save($entity));
  599. }
  600. /**
  601. * Tests the existsIn with coflicting columns
  602. *
  603. * @group save
  604. * @return void
  605. */
  606. public function testExistsInAliasPrefix()
  607. {
  608. $entity = new Entity([
  609. 'title' => 'An Article',
  610. 'author_id' => 500
  611. ]);
  612. $table = TableRegistry::get('Articles');
  613. $table->belongsTo('Authors');
  614. $rules = $table->rulesChecker();
  615. $rules->add($rules->existsIn('author_id', 'Authors'));
  616. $table->Authors->eventManager()->on('Model.beforeFind', function ($event, $query) {
  617. $query->leftJoin(['a2' => 'authors']);
  618. });
  619. $this->assertFalse($table->save($entity));
  620. $this->assertEquals(['_existsIn' => 'This value does not exist'], $entity->errors('author_id'));
  621. }
  622. /**
  623. * Tests that using an array in existsIn() sets the error message correctly
  624. *
  625. * @return
  626. */
  627. public function testExistsInErrorWithArrayField()
  628. {
  629. $entity = new Entity([
  630. 'title' => 'An Article',
  631. 'author_id' => 500
  632. ]);
  633. $table = TableRegistry::get('Articles');
  634. $table->belongsTo('Authors');
  635. $rules = $table->rulesChecker();
  636. $rules->add($rules->existsIn(['author_id'], 'Authors'));
  637. $this->assertFalse($table->save($entity));
  638. $this->assertEquals(['_existsIn' => 'This value does not exist'], $entity->errors('author_id'));
  639. }
  640. /**
  641. * Tests using rules to prevent delete operations
  642. *
  643. * @group delete
  644. * @return void
  645. */
  646. public function testDeleteRules()
  647. {
  648. $table = TableRegistry::get('Articles');
  649. $rules = $table->rulesChecker();
  650. $rules->addDelete(function ($entity) {
  651. return false;
  652. });
  653. $entity = $table->get(1);
  654. $this->assertFalse($table->delete($entity));
  655. }
  656. /**
  657. * Checks that it is possible to pass custom options to rules when saving
  658. *
  659. * @group save
  660. * @return void
  661. */
  662. public function testCustomOptionsPassingSave()
  663. {
  664. $entity = new Entity([
  665. 'name' => 'jose'
  666. ]);
  667. $table = TableRegistry::get('Authors');
  668. $rules = $table->rulesChecker();
  669. $rules->add(function ($entity, $options) {
  670. $this->assertEquals('bar', $options['foo']);
  671. $this->assertEquals('option', $options['another']);
  672. return false;
  673. }, ['another' => 'option']);
  674. $this->assertFalse($table->save($entity, ['foo' => 'bar']));
  675. }
  676. /**
  677. * Tests passing custom options to rules from delete
  678. *
  679. * @group delete
  680. * @return void
  681. */
  682. public function testCustomOptionsPassingDelete()
  683. {
  684. $table = TableRegistry::get('Articles');
  685. $rules = $table->rulesChecker();
  686. $rules->addDelete(function ($entity, $options) {
  687. $this->assertEquals('bar', $options['foo']);
  688. $this->assertEquals('option', $options['another']);
  689. return false;
  690. }, ['another' => 'option']);
  691. $entity = $table->get(1);
  692. $this->assertFalse($table->delete($entity, ['foo' => 'bar']));
  693. }
  694. /**
  695. * Test adding rules that return error string
  696. *
  697. * @group save
  698. * @return void
  699. */
  700. public function testCustomErrorMessageFromRule()
  701. {
  702. $entity = new Entity([
  703. 'name' => 'larry'
  704. ]);
  705. $table = TableRegistry::get('Authors');
  706. $rules = $table->rulesChecker();
  707. $rules->add(function () {
  708. return 'So much nope';
  709. }, ['errorField' => 'name']);
  710. $this->assertFalse($table->save($entity));
  711. $this->assertEquals(['So much nope'], $entity->errors('name'));
  712. }
  713. /**
  714. * Test adding rules with no errorField do not accept strings
  715. *
  716. * @group save
  717. * @return void
  718. */
  719. public function testCustomErrorMessageFromRuleNoErrorField()
  720. {
  721. $entity = new Entity([
  722. 'name' => 'larry'
  723. ]);
  724. $table = TableRegistry::get('Authors');
  725. $rules = $table->rulesChecker();
  726. $rules->add(function () {
  727. return 'So much nope';
  728. });
  729. $this->assertFalse($table->save($entity));
  730. $this->assertEmpty($entity->errors());
  731. }
  732. /**
  733. * Tests that using existsIn for a hasMany association will not be called
  734. * as the foreign key for the association was automatically validated already.
  735. *
  736. * @group save
  737. * @return void
  738. */
  739. public function testAvoidExistsInOnAutomaticSaving()
  740. {
  741. $entity = new \Cake\ORM\Entity([
  742. 'name' => 'Jose'
  743. ]);
  744. $entity->articles = [
  745. new \Cake\ORM\Entity([
  746. 'title' => '1',
  747. 'body' => 'A body'
  748. ]),
  749. new \Cake\ORM\Entity([
  750. 'title' => 'Another Title',
  751. 'body' => 'Another body'
  752. ])
  753. ];
  754. $table = TableRegistry::get('authors');
  755. $table->hasMany('articles');
  756. $table->association('articles')->belongsTo('authors');
  757. $checker = $table->association('articles')->target()->rulesChecker();
  758. $checker->add(function ($entity, $options) use ($checker) {
  759. $rule = $checker->existsIn('author_id', 'authors');
  760. $id = $entity->author_id;
  761. $entity->author_id = 5000;
  762. $result = $rule($entity, $options);
  763. $this->assertTrue($result);
  764. $entity->author_id = $id;
  765. return true;
  766. });
  767. $this->assertSame($entity, $table->save($entity));
  768. }
  769. }