AssociationCollectionTest.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  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\AssociationCollection;
  17. use Cake\ORM\Association\BelongsTo;
  18. use Cake\ORM\Association\BelongsToMany;
  19. use Cake\ORM\Entity;
  20. use Cake\TestSuite\TestCase;
  21. /**
  22. * AssociationCollection test case.
  23. */
  24. class AssociationCollectionTest extends TestCase
  25. {
  26. /**
  27. * @var AssociationCollection
  28. */
  29. public $associations;
  30. /**
  31. * setup
  32. *
  33. * @return void
  34. */
  35. public function setUp()
  36. {
  37. parent::setUp();
  38. $this->associations = new AssociationCollection();
  39. }
  40. /**
  41. * Test the simple add/has and get methods.
  42. *
  43. * @return void
  44. */
  45. public function testAddHasRemoveAndGet()
  46. {
  47. $this->assertFalse($this->associations->has('users'));
  48. $this->assertFalse($this->associations->has('Users'));
  49. $this->assertNull($this->associations->get('users'));
  50. $this->assertNull($this->associations->get('Users'));
  51. $belongsTo = new BelongsTo('');
  52. $this->assertSame($belongsTo, $this->associations->add('Users', $belongsTo));
  53. $this->assertTrue($this->associations->has('users'));
  54. $this->assertTrue($this->associations->has('Users'));
  55. $this->assertSame($belongsTo, $this->associations->get('users'));
  56. $this->assertSame($belongsTo, $this->associations->get('Users'));
  57. $this->assertNull($this->associations->remove('Users'));
  58. $this->assertFalse($this->associations->has('users'));
  59. $this->assertFalse($this->associations->has('Users'));
  60. $this->assertNull($this->associations->get('users'));
  61. $this->assertNull($this->associations->get('Users'));
  62. }
  63. /**
  64. * Test removeAll method
  65. *
  66. * @return void
  67. */
  68. public function testRemoveAll()
  69. {
  70. $this->assertEmpty($this->associations->keys());
  71. $belongsTo = new BelongsTo('');
  72. $this->assertSame($belongsTo, $this->associations->add('Users', $belongsTo));
  73. $belongsToMany = new BelongsToMany('');
  74. $this->assertSame($belongsToMany, $this->associations->add('Cart', $belongsToMany));
  75. $this->associations->removeAll();
  76. $this->assertEmpty($this->associations->keys());
  77. }
  78. /**
  79. * Test getting associations by property.
  80. *
  81. * @return void
  82. */
  83. public function testGetByProperty()
  84. {
  85. $table = $this->getMockBuilder('Cake\ORM\Table')
  86. ->setMethods(['table'])
  87. ->getMock();
  88. $table->schema([]);
  89. $belongsTo = new BelongsTo('Users', [
  90. 'sourceTable' => $table
  91. ]);
  92. $this->assertEquals('user', $belongsTo->property());
  93. $this->associations->add('Users', $belongsTo);
  94. $this->assertNull($this->associations->get('user'));
  95. $this->assertSame($belongsTo, $this->associations->getByProperty('user'));
  96. }
  97. /**
  98. * Test associations with plugin names.
  99. *
  100. * @return void
  101. */
  102. public function testAddHasRemoveGetWithPlugin()
  103. {
  104. $this->assertFalse($this->associations->has('Photos.Photos'));
  105. $this->assertFalse($this->associations->has('Photos'));
  106. $belongsTo = new BelongsTo('');
  107. $this->assertSame($belongsTo, $this->associations->add('Photos.Photos', $belongsTo));
  108. $this->assertTrue($this->associations->has('Photos'));
  109. $this->assertFalse($this->associations->has('Photos.Photos'));
  110. }
  111. /**
  112. * Test keys()
  113. *
  114. * @return void
  115. */
  116. public function testKeys()
  117. {
  118. $belongsTo = new BelongsTo('');
  119. $this->associations->add('Users', $belongsTo);
  120. $this->associations->add('Categories', $belongsTo);
  121. $this->assertEquals(['users', 'categories'], $this->associations->keys());
  122. $this->associations->remove('Categories');
  123. $this->assertEquals(['users'], $this->associations->keys());
  124. }
  125. /**
  126. * Data provider for AssociationCollection::type
  127. */
  128. public function associationCollectionType()
  129. {
  130. return [
  131. ['BelongsTo', 'BelongsToMany'],
  132. ['belongsTo', 'belongsToMany'],
  133. ['belongsto', 'belongstomany']
  134. ];
  135. }
  136. /**
  137. * Test getting association names by type.
  138. *
  139. * @param string $belongsToStr
  140. * @param string $belongsToManyStr
  141. * @dataProvider associationCollectionType
  142. */
  143. public function testType($belongsToStr, $belongsToManyStr)
  144. {
  145. $belongsTo = new BelongsTo('');
  146. $this->associations->add('Users', $belongsTo);
  147. $belongsToMany = new BelongsToMany('');
  148. $this->associations->add('Tags', $belongsToMany);
  149. $this->assertSame([$belongsTo], $this->associations->type($belongsToStr));
  150. $this->assertSame([$belongsToMany], $this->associations->type($belongsToManyStr));
  151. $this->assertSame([$belongsTo, $belongsToMany], $this->associations->type([$belongsToStr, $belongsToManyStr]));
  152. }
  153. /**
  154. * Type should return empty array.
  155. *
  156. * @return void
  157. */
  158. public function hasTypeReturnsEmptyArray()
  159. {
  160. foreach (['HasMany', 'hasMany', 'FooBar', 'DoesNotExist'] as $value) {
  161. $this->assertSame([], $this->associations->type($value));
  162. }
  163. }
  164. /**
  165. * test cascading deletes.
  166. *
  167. * @return void
  168. */
  169. public function testCascadeDelete()
  170. {
  171. $mockOne = $this->getMockBuilder('Cake\ORM\Association\BelongsTo')
  172. ->setConstructorArgs([''])
  173. ->getMock();
  174. $mockTwo = $this->getMockBuilder('Cake\ORM\Association\HasMany')
  175. ->setConstructorArgs([''])
  176. ->getMock();
  177. $entity = new Entity();
  178. $options = ['option' => 'value'];
  179. $this->associations->add('One', $mockOne);
  180. $this->associations->add('Two', $mockTwo);
  181. $mockOne->expects($this->once())
  182. ->method('cascadeDelete')
  183. ->with($entity, $options);
  184. $mockTwo->expects($this->once())
  185. ->method('cascadeDelete')
  186. ->with($entity, $options);
  187. $this->assertNull($this->associations->cascadeDelete($entity, $options));
  188. }
  189. /**
  190. * Test saving parent associations
  191. *
  192. * @return void
  193. */
  194. public function testSaveParents()
  195. {
  196. $table = $this->getMockBuilder('Cake\ORM\Table')
  197. ->setMethods(['table'])
  198. ->getMock();
  199. $table->schema([]);
  200. $mockOne = $this->getMockBuilder('Cake\ORM\Association\BelongsTo')
  201. ->setMethods(['saveAssociated'])
  202. ->setConstructorArgs(['Parent', [
  203. 'sourceTable' => $table,
  204. ]])
  205. ->getMock();
  206. $mockTwo = $this->getMockBuilder('Cake\ORM\Association\HasMany')
  207. ->setMethods(['saveAssociated'])
  208. ->setConstructorArgs(['Child', [
  209. 'sourceTable' => $table
  210. ]])
  211. ->getMock();
  212. $this->associations->add('Parent', $mockOne);
  213. $this->associations->add('Child', $mockTwo);
  214. $entity = new Entity();
  215. $entity->set('parent', ['key' => 'value']);
  216. $entity->set('child', ['key' => 'value']);
  217. $options = ['option' => 'value'];
  218. $mockOne->expects($this->once())
  219. ->method('saveAssociated')
  220. ->with($entity, $options)
  221. ->will($this->returnValue(true));
  222. $mockTwo->expects($this->never())
  223. ->method('saveAssociated');
  224. $result = $this->associations->saveParents(
  225. $table,
  226. $entity,
  227. ['Parent', 'Child'],
  228. $options
  229. );
  230. $this->assertTrue($result, 'Save should work.');
  231. }
  232. /**
  233. * Test saving filtered parent associations.
  234. *
  235. * @return void
  236. */
  237. public function testSaveParentsFiltered()
  238. {
  239. $table = $this->getMockBuilder('Cake\ORM\Table')
  240. ->setMethods(['table'])
  241. ->getMock();
  242. $table->schema([]);
  243. $mockOne = $this->getMockBuilder('Cake\ORM\Association\BelongsTo')
  244. ->setMethods(['saveAssociated'])
  245. ->setConstructorArgs(['Parents', [
  246. 'sourceTable' => $table,
  247. ]])
  248. ->getMock();
  249. $mockTwo = $this->getMockBuilder('Cake\ORM\Association\BelongsTo')
  250. ->setMethods(['saveAssociated'])
  251. ->setConstructorArgs(['Categories', [
  252. 'sourceTable' => $table
  253. ]])
  254. ->getMock();
  255. $this->associations->add('Parents', $mockOne);
  256. $this->associations->add('Categories', $mockTwo);
  257. $entity = new Entity();
  258. $entity->set('parent', ['key' => 'value']);
  259. $entity->set('category', ['key' => 'value']);
  260. $options = ['atomic' => true];
  261. $mockOne->expects($this->once())
  262. ->method('saveAssociated')
  263. ->with($entity, ['atomic' => true, 'associated' => ['Others']])
  264. ->will($this->returnValue(true));
  265. $mockTwo->expects($this->never())
  266. ->method('saveAssociated');
  267. $result = $this->associations->saveParents(
  268. $table,
  269. $entity,
  270. ['Parents' => ['associated' => ['Others']]],
  271. $options
  272. );
  273. $this->assertTrue($result, 'Save should work.');
  274. }
  275. /**
  276. * Test saving filtered child associations.
  277. *
  278. * @return void
  279. */
  280. public function testSaveChildrenFiltered()
  281. {
  282. $table = $this->getMockBuilder('Cake\ORM\Table')
  283. ->setMethods(['table'])
  284. ->getMock();
  285. $table->schema([]);
  286. $mockOne = $this->getMockBuilder('Cake\ORM\Association\HasMany')
  287. ->setMethods(['saveAssociated'])
  288. ->setConstructorArgs(['Comments', [
  289. 'sourceTable' => $table,
  290. ]])
  291. ->getMock();
  292. $mockTwo = $this->getMockBuilder('Cake\ORM\Association\HasOne')
  293. ->setMethods(['saveAssociated'])
  294. ->setConstructorArgs(['Profiles', [
  295. 'sourceTable' => $table
  296. ]])
  297. ->getMock();
  298. $this->associations->add('Comments', $mockOne);
  299. $this->associations->add('Profiles', $mockTwo);
  300. $entity = new Entity();
  301. $entity->set('comments', ['key' => 'value']);
  302. $entity->set('profile', ['key' => 'value']);
  303. $options = ['atomic' => true];
  304. $mockOne->expects($this->once())
  305. ->method('saveAssociated')
  306. ->with($entity, $options + ['associated' => ['Other']])
  307. ->will($this->returnValue(true));
  308. $mockTwo->expects($this->never())
  309. ->method('saveAssociated');
  310. $result = $this->associations->saveChildren(
  311. $table,
  312. $entity,
  313. ['Comments' => ['associated' => ['Other']]],
  314. $options
  315. );
  316. $this->assertTrue($result, 'Should succeed.');
  317. }
  318. /**
  319. * Test exceptional case.
  320. *
  321. * @expectedException \InvalidArgumentException
  322. * @expectedExceptionMessage Cannot save Profiles, it is not associated to Users
  323. */
  324. public function testErrorOnUnknownAlias()
  325. {
  326. $table = $this->getMockBuilder('Cake\ORM\Table')
  327. ->setMethods(['save'])
  328. ->setConstructorArgs([['alias' => 'Users']])
  329. ->getMock();
  330. $entity = new Entity();
  331. $entity->set('profile', ['key' => 'value']);
  332. $this->associations->saveChildren(
  333. $table,
  334. $entity,
  335. ['Profiles'],
  336. ['atomic' => true]
  337. );
  338. }
  339. /**
  340. * Tests the normalizeKeys method
  341. *
  342. * @return void
  343. */
  344. public function testNormalizeKeys()
  345. {
  346. $this->assertSame([], $this->associations->normalizeKeys([]));
  347. $this->assertSame([], $this->associations->normalizeKeys(false));
  348. $assocs = ['a', 'b', 'd' => ['something']];
  349. $expected = ['a' => [], 'b' => [], 'd' => ['something']];
  350. $this->assertSame($expected, $this->associations->normalizeKeys($assocs));
  351. $belongsTo = new BelongsTo('');
  352. $this->associations->add('users', $belongsTo);
  353. $this->associations->add('categories', $belongsTo);
  354. $expected = ['users' => [], 'categories' => []];
  355. $this->assertSame($expected, $this->associations->normalizeKeys(true));
  356. }
  357. /**
  358. * Ensure that the association collection can be iterated.
  359. *
  360. * @return void
  361. */
  362. public function testAssociationsCanBeIterated()
  363. {
  364. $belongsTo = new BelongsTo('');
  365. $this->associations->add('Users', $belongsTo);
  366. $belongsToMany = new BelongsToMany('');
  367. $this->associations->add('Cart', $belongsToMany);
  368. $expected = ['users' => $belongsTo, 'cart' => $belongsToMany];
  369. $result = iterator_to_array($this->associations, true);
  370. $this->assertSame($expected, $result);
  371. }
  372. }