From b82a09f359e681e377f9cb4386a1e677516611d2 Mon Sep 17 00:00:00 2001 From: Jose Lorenzo Rodriguez Date: Fri, 22 Aug 2014 12:48:29 +0200 Subject: [PATCH] Using Association::find() in Association::attachTo() This allows us to use defined custom finders even for joinable associations. Removed unit tests that were hard to follow and were fragile, the code they covered is also covered by a few integration tests. --- src/ORM/Association.php | 3 +- .../ORM/Association/BelongsToManyTest.php | 630 ------------------ .../ORM/Association/BelongsToTest.php | 71 -- .../TestCase/ORM/Association/HasManyTest.php | 242 ------- tests/TestCase/ORM/Association/HasOneTest.php | 72 -- 5 files changed, 1 insertion(+), 1017 deletions(-) diff --git a/src/ORM/Association.php b/src/ORM/Association.php index 11e255b0c01..f16dbdb3e30 100644 --- a/src/ORM/Association.php +++ b/src/ORM/Association.php @@ -433,7 +433,6 @@ public function attachTo(Query $query, array $options = []) { 'type' => empty($options['matching']) ? $this->joinType() : 'INNER', 'table' => $target->table() ]; - $options['conditions'] = array_merge($this->conditions(), $options['conditions']); if (!empty($options['foreignKey'])) { $joinCondition = $this->_joinCondition($options); @@ -442,7 +441,7 @@ public function attachTo(Query $query, array $options = []) { } } - $dummy = $target->query()->eagerLoaded(true); + $dummy = $this->find()->eagerLoaded(true); if (!empty($options['queryBuilder'])) { $dummy = $options['queryBuilder']($dummy); if (!($dummy instanceof Query)) { diff --git a/tests/TestCase/ORM/Association/BelongsToManyTest.php b/tests/TestCase/ORM/Association/BelongsToManyTest.php index 009bcd5e768..96188a24bfd 100644 --- a/tests/TestCase/ORM/Association/BelongsToManyTest.php +++ b/tests/TestCase/ORM/Association/BelongsToManyTest.php @@ -219,559 +219,6 @@ public function testSaveStrategyInvalid() { $assoc = new BelongsToMany('Test', ['saveStrategy' => 'depsert']); } -/** - * Tests that the correct join and fields are attached to a query depending on - * the association config - * - * @return void - */ - public function testAttachTo() { - $query = $this->getMock('\Cake\ORM\Query', ['join', 'select'], [null, null]); - $config = [ - 'sourceTable' => $this->article, - 'targetTable' => $this->tag, - 'conditions' => ['Tags.name' => 'cake'] - ]; - $association = new BelongsToMany('Tags', $config); - $query->expects($this->at(0))->method('join')->with([ - 'Tags' => [ - 'conditions' => new QueryExpression([ - 'Tags.name' => 'cake' - ], $this->tagsTypeMap), - 'type' => 'INNER', - 'table' => 'tags' - ] - ]); - - $field1 = new IdentifierExpression('ArticlesTags.article_id'); - $field2 = new IdentifierExpression('ArticlesTags.tag_id'); - - $query->expects($this->at(2))->method('join')->with([ - 'ArticlesTags' => [ - 'conditions' => new QueryExpression([ - ['Articles.id' => $field1], - ['Tags.id' => $field2] - ], $this->articlesTagsTypeMap), - 'type' => 'INNER', - 'table' => 'articles_tags' - ] - ]); - $query->expects($this->at(1))->method('select')->with([ - 'Tags__id' => 'Tags.id', - 'Tags__name' => 'Tags.name', - ]); - $query->expects($this->at(3))->method('select')->with([ - 'ArticlesTags__article_id' => 'ArticlesTags.article_id', - 'ArticlesTags__tag_id' => 'ArticlesTags.tag_id', - ]); - $association->attachTo($query); - } - -/** - * Tests that it is possible to avoid fields inclusion for the associated table - * - * @return void - */ - public function testAttachToNoFields() { - $query = $this->getMock('\Cake\ORM\Query', ['join', 'select'], [null, null]); - $config = [ - 'sourceTable' => $this->article, - 'targetTable' => $this->tag, - 'conditions' => ['Tags.name' => 'cake'] - ]; - $association = new BelongsToMany('Tags', $config); - $query->expects($this->at(0))->method('join')->with([ - 'Tags' => [ - 'conditions' => new QueryExpression([ - 'Tags.name' => 'cake' - ], $this->tagsTypeMap), - 'type' => 'INNER', - 'table' => 'tags' - ] - ]); - - $field1 = new IdentifierExpression('ArticlesTags.article_id'); - $field2 = new IdentifierExpression('ArticlesTags.tag_id'); - - $query->expects($this->at(1))->method('join')->with([ - 'ArticlesTags' => [ - 'conditions' => new QueryExpression([ - ['Articles.id' => $field1], - ['Tags.id' => $field2] - ], $this->articlesTagsTypeMap), - 'type' => 'INNER', - 'table' => 'articles_tags' - ] - ]); - $query->expects($this->never())->method('select'); - $association->attachTo($query, ['includeFields' => false]); - } - -/** - * Tests that by supplying a query builder function, it is possible to add fields - * and conditions to an association - * - * @return void - */ - public function testAttachToWithQueryBuilder() { - $query = $this->getMock('\Cake\ORM\Query', ['join', 'select'], [null, null]); - $config = [ - 'sourceTable' => $this->article, - 'targetTable' => $this->tag, - 'conditions' => ['Tags.name' => 'cake'] - ]; - $association = new BelongsToMany('Tags', $config); - $query->expects($this->at(0))->method('join')->with([ - 'Tags' => [ - 'conditions' => new QueryExpression([ - 'a' => 1, - 'Tags.name' => 'cake', - ], $this->tagsTypeMap), - 'type' => 'INNER', - 'table' => 'tags' - ] - ]); - - $field1 = new IdentifierExpression('ArticlesTags.article_id'); - $field2 = new IdentifierExpression('ArticlesTags.tag_id'); - - $query->expects($this->at(2))->method('join')->with([ - 'ArticlesTags' => [ - 'conditions' => new QueryExpression([ - ['Articles.id' => $field1], - ['Tags.id' => $field2] - ], $this->articlesTagsTypeMap), - 'type' => 'INNER', - 'table' => 'articles_tags' - ] - ]); - - $query->expects($this->once())->method('select') - ->with([ - 'Tags__a' => 'Tags.a', - 'Tags__b' => 'Tags.b' - ]); - $builder = function($q) { - return $q->select(['a', 'b'])->where(['a' => 1]); - }; - $association->attachTo($query, [ - 'includeFields' => false, - 'queryBuilder' => $builder - ]); - } - -/** - * Tests that using belongsToMany with a table having a multi column primary - * key will work if the foreign key is passed - * - * @return void - */ - public function testAttachToMultiPrimaryKey() { - $query = $this->getMock('\Cake\ORM\Query', ['join', 'select'], [null, null]); - $config = [ - 'sourceTable' => $this->article, - 'targetTable' => $this->tag, - 'conditions' => ['Tags.name' => 'cake'], - 'foreignKey' => ['article_id', 'article_site_id'], - 'targetForeignKey' => ['tag_id', 'tag_site_id'] - ]; - $this->article->primaryKey(['id', 'site_id']); - $this->tag->primaryKey(['id', 'my_site_id']); - $association = new BelongsToMany('Tags', $config); - $query->expects($this->at(0))->method('join')->with([ - 'Tags' => [ - 'conditions' => new QueryExpression([ - 'Tags.name' => 'cake' - ], $this->tagsTypeMap), - 'type' => 'INNER', - 'table' => 'tags' - ] - ]); - - $fieldA = new IdentifierExpression('ArticlesTags.article_id'); - $fieldB = new IdentifierExpression('ArticlesTags.article_site_id'); - $fieldC = new IdentifierExpression('ArticlesTags.tag_id'); - $fieldD = new IdentifierExpression('ArticlesTags.tag_site_id'); - - $query->expects($this->at(1))->method('join')->with([ - 'ArticlesTags' => [ - 'conditions' => new QueryExpression([ - ['Articles.id' => $fieldA, 'Articles.site_id' => $fieldB], - ['Tags.id' => $fieldC, 'Tags.my_site_id' => $fieldD] - ], $this->articlesTagsTypeMap), - 'type' => 'INNER', - 'table' => 'articles_tags' - ] - ]); - $query->expects($this->never())->method('select'); - $association->attachTo($query, ['includeFields' => false]); - } - -/** - * Test the eager loader method with no extra options - * - * @return void - */ - public function testEagerLoader() { - $config = [ - 'sourceTable' => $this->article, - 'targetTable' => $this->tag, - ]; - $association = new BelongsToMany('Tags', $config); - $keys = [1, 2, 3, 4]; - $query = $this->getMock('Cake\ORM\Query', ['all', 'matching'], [null, null]); - - $this->tag->expects($this->once()) - ->method('find') - ->with('all') - ->will($this->returnValue($query)); - - $results = [ - ['id' => 1, 'name' => 'foo', 'articles_tags' => ['article_id' => 1]], - ['id' => 2, 'name' => 'bar', 'articles_tags' => ['article_id' => 2]] - ]; - $query->expects($this->once()) - ->method('all') - ->will($this->returnValue($results)); - - $query->expects($this->once())->method('matching') - ->will($this->returnCallback(function($alias, $callable) use ($query, $keys) { - $this->assertEquals('ArticlesTags', $alias); - $q = $this->getMock('Cake\ORM\Query', [], [null, null]); - - $q->expects($this->once())->method('andWhere') - ->with(['ArticlesTags.article_id IN' => $keys]) - ->will($this->returnSelf()); - - $this->assertSame($q, $callable($q)); - return $query; - })); - - $query->hydrate(false); - - $callable = $association->eagerLoader(compact('keys', 'query')); - $row = ['Articles__id' => 1, 'title' => 'article 1']; - $result = $callable($row); - $row['Tags'] = [ - ['id' => 1, 'name' => 'foo', '_joinData' => ['article_id' => 1]] - ]; - $this->assertEquals($row, $result); - - $row = ['Articles__id' => 2, 'title' => 'article 2']; - $result = $callable($row); - $row['Tags'] = [ - ['id' => 2, 'name' => 'bar', '_joinData' => ['article_id' => 2]] - ]; - $this->assertEquals($row, $result); - } - -/** - * Test the eager loader method with default query clauses - * - * @return void - */ - public function testEagerLoaderWithDefaults() { - $config = [ - 'sourceTable' => $this->article, - 'targetTable' => $this->tag, - 'conditions' => ['Tags.name' => 'foo'], - 'sort' => ['id' => 'ASC'], - ]; - $association = new BelongsToMany('Tags', $config); - $keys = [1, 2, 3, 4]; - $methods = ['all', 'matching', 'where', 'order']; - $query = $this->getMock('Cake\ORM\Query', $methods, [null, null]); - $this->tag->expects($this->once()) - ->method('find') - ->with('all') - ->will($this->returnValue($query)); - $results = [ - ['id' => 1, 'name' => 'foo', 'articles_tags' => ['article_id' => 1]], - ['id' => 2, 'name' => 'bar', 'articles_tags' => ['article_id' => 2]] - ]; - $query->expects($this->once()) - ->method('all') - ->will($this->returnValue($results)); - - $query->expects($this->once())->method('matching') - ->will($this->returnCallback(function($alias, $callable) use ($query, $keys) { - $this->assertEquals('ArticlesTags', $alias); - $q = $this->getMock('Cake\ORM\Query', [], [null, null]); - - $q->expects($this->once())->method('andWhere') - ->with(['ArticlesTags.article_id IN' => $keys]) - ->will($this->returnSelf()); - - $this->assertSame($q, $callable($q)); - return $query; - })); - - $query->expects($this->at(0))->method('where') - ->with(['Tags.name' => 'foo']) - ->will($this->returnSelf()); - $query->expects($this->at(1))->method('where') - ->with([]) - ->will($this->returnSelf()); - - $query->expects($this->once())->method('order') - ->with(['id' => 'ASC']) - ->will($this->returnSelf()); - - $query->hydrate(false); - - $association->eagerLoader(compact('keys', 'query')); - } - -/** - * Test the eager loader method with overridden query clauses - * - * @return void - */ - public function testEagerLoaderWithOverrides() { - $config = [ - 'sourceTable' => $this->article, - 'targetTable' => $this->tag, - 'conditions' => ['Tags.name' => 'foo'], - 'sort' => ['id' => 'ASC'], - ]; - $association = new BelongsToMany('Tags', $config); - $keys = [1, 2, 3, 4]; - $methods = ['all', 'matching', 'where', 'order', 'select']; - $query = $this->getMock('Cake\ORM\Query', $methods, [null, null]); - $this->tag->expects($this->once())->method('find')->with('all') - ->will($this->returnValue($query)); - $results = [ - ['id' => 1, 'name' => 'foo', 'articles_tags' => ['article_id' => 1]], - ['id' => 2, 'name' => 'bar', 'articles_tags' => ['article_id' => 2]] - ]; - $query->expects($this->once())->method('all') - ->will($this->returnValue($results)); - - $query->expects($this->once())->method('matching') - ->will($this->returnCallback(function($alias, $callable) use ($query, $keys) { - $this->assertEquals('ArticlesTags', $alias); - $q = $this->getMock('Cake\ORM\Query', [], [null, null]); - - $q->expects($this->once())->method('andWhere') - ->with(['ArticlesTags.article_id IN' => $keys]) - ->will($this->returnSelf()); - - $this->assertSame($q, $callable($q)); - return $query; - })); - - $query->expects($this->at(0))->method('where') - ->with(['Tags.name' => 'foo']) - ->will($this->returnSelf()); - - $query->expects($this->at(1))->method('where') - ->with(['Tags.id !=' => 3]) - ->will($this->returnSelf()); - - $query->expects($this->once())->method('order') - ->with(['name' => 'DESC']) - ->will($this->returnSelf()); - - $query->expects($this->once())->method('select') - ->with([ - 'Tags__name' => 'Tags.name', - 'ArticlesTags__article_id' => 'ArticlesTags.article_id' - ]) - ->will($this->returnSelf()); - - $query->hydrate(false); - - $association->eagerLoader([ - 'conditions' => ['Tags.id !=' => 3], - 'sort' => ['name' => 'DESC'], - 'fields' => ['name', 'ArticlesTags.article_id'], - 'keys' => $keys, - 'query' => $query - ]); - } - -/** - * Test the eager loader method with default query clauses - * - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage You are required to select the "ArticlesTags.article_id" - * @return void - */ - public function testEagerLoaderFieldsException() { - $config = [ - 'sourceTable' => $this->article, - 'targetTable' => $this->tag, - 'conditions' => ['Tags.name' => 'foo'], - 'sort' => ['id' => 'ASC'], - ]; - $association = new BelongsToMany('Tags', $config); - $keys = [1, 2, 3, 4]; - $methods = ['all', 'contain', 'where', 'order', 'select']; - $query = $this->getMock('Cake\ORM\Query', $methods, [null, null]); - $this->tag->expects($this->once()) - ->method('find') - ->with('all') - ->will($this->returnValue($query)); - $query->expects($this->any())->method('contain')->will($this->returnSelf()); - - $query->expects($this->exactly(2))->method('where')->will($this->returnSelf()); - - $association->eagerLoader([ - 'keys' => $keys, - 'fields' => ['name'], - 'query' => $query - ]); - } - -/** - * Tests eager loading using subquery - * - * @return void - */ - public function testEagerLoaderSubquery() { - $config = [ - 'sourceTable' => $this->article, - 'targetTable' => $this->tag, - 'conditions' => ['Tags.name' => 'foo'], - 'sort' => ['id' => 'ASC'], - ]; - $association = new BelongsToMany('Tags', $config); - $parent = (new Query(null, $this->article)) - ->join(['foo' => ['table' => 'foo', 'type' => 'inner', 'conditions' => []]]) - ->join(['bar' => ['table' => 'bar', 'type' => 'left', 'conditions' => []]]); - $parent->hydrate(false); - - $query = $this->getMock( - 'Cake\ORM\Query', - ['all', 'where', 'andWhere', 'order', 'select', 'matching'], - [null, $this->article] - ); - - $query->hydrate(false); - - $this->tag->expects($this->once()) - ->method('find') - ->with('all') - ->will($this->returnValue($query)); - $results = [ - ['id' => 1, 'name' => 'foo', 'articles_tags' => ['article_id' => 1]], - ['id' => 2, 'name' => 'bar', 'articles_tags' => ['article_id' => 2]] - ]; - $query->expects($this->once()) - ->method('all') - ->will($this->returnValue($results)); - - $expected = clone $parent; - $joins = $expected->join(); - unset($joins['bar']); - $expected - ->contain([], true) - ->select(['Articles__id' => 'Articles.id'], true) - ->join($joins, [], true); - - $query->expects($this->at(0))->method('where') - ->with(['Tags.name' => 'foo']) - ->will($this->returnSelf()); - - $query->expects($this->at(1))->method('where') - ->with([]) - ->will($this->returnSelf()); - - $query->expects($this->once())->method('matching') - ->will($this->returnCallback(function($alias, $callable) use ($query, $expected) { - $this->assertEquals('ArticlesTags', $alias); - $q = $this->getMock('Cake\ORM\Query', [], [null, null]); - - $q->expects($this->once())->method('andWhere') - ->with(['ArticlesTags.article_id IN' => $expected]) - ->will($this->returnSelf()); - - $this->assertSame($q, $callable($q)); - return $query; - })); - - $callable = $association->eagerLoader([ - 'query' => $parent, 'strategy' => BelongsToMany::STRATEGY_SUBQUERY, - 'keys' => [] - ]); - - $row['Tags'] = [ - ['id' => 1, 'name' => 'foo', '_joinData' => ['article_id' => 1]] - ]; - $row['Articles__id'] = 1; - $result = $callable($row); - $this->assertEquals($row, $result); - - $row['Tags'] = [ - ['id' => 2, 'name' => 'bar', '_joinData' => ['article_id' => 2]] - ]; - $row['Articles__id'] = 2; - $result = $callable($row); - $this->assertEquals($row, $result); - } - -/** - * Tests eagerLoader with queryBuilder - * - * @return void - */ - public function testEagerLoaderWithQueryBuilder() { - $config = [ - 'sourceTable' => $this->article, - 'targetTable' => $this->tag, - ]; - $association = new BelongsToMany('Tags', $config); - $keys = [1, 2, 3, 4]; - $query = $this->getMock( - 'Cake\ORM\Query', - ['all', 'matching', 'andWhere', 'limit'], - [null, null] - ); - - $this->tag->expects($this->once()) - ->method('find') - ->with('all') - ->will($this->returnValue($query)); - - $results = [ - ['id' => 1, 'name' => 'foo', 'articles_tags' => ['article_id' => 1]], - ['id' => 2, 'name' => 'bar', 'articles_tags' => ['article_id' => 2]] - ]; - $query->expects($this->once()) - ->method('all') - ->will($this->returnValue($results)); - - $query->expects($this->once())->method('matching') - ->will($this->returnCallback(function($alias, $callable) use ($query, $keys) { - $this->assertEquals('ArticlesTags', $alias); - $q = $this->getMock('Cake\ORM\Query', [], [null, null]); - - $q->expects($this->once())->method('andWhere') - ->with(['ArticlesTags.article_id IN' => $keys]) - ->will($this->returnSelf()); - - $this->assertSame($q, $callable($q)); - return $query; - })); - - $query->hydrate(false); - - $query->expects($this->once()) - ->method('andWhere') - ->with(['foo' => 1]) - ->will($this->returnSelf()); - - $query->expects($this->once()) - ->method('limit') - ->with(1) - ->will($this->returnSelf()); - - $queryBuilder = function($q) { - return $q->andWhere(['foo' => 1])->limit(1); - }; - $association->eagerLoader(compact('keys', 'query', 'queryBuilder')); - } - /** * Test the eager loader method with no extra options * @@ -1592,81 +1039,4 @@ public function testPropertyNoPlugin() { $this->assertEquals('tags', $association->property()); } -/** - * Tests that attaching an association to a query will trigger beforeFind - * for the target table - * - * @return void - */ - public function testAttachToBeforeFind() { - $query = $this->getMock('\Cake\ORM\Query', ['join', 'select'], [null, null]); - $config = [ - 'sourceTable' => $this->article, - 'targetTable' => $this->tag, - ]; - $table = TableRegistry::get('ArticlesTags'); - $association = new BelongsToMany('Tags', $config); - $listener = $this->getMock('stdClass', ['__invoke']); - $this->tag->eventManager()->attach($listener, 'Model.beforeFind'); - $listener->expects($this->once())->method('__invoke') - ->with( - $this->isInstanceOf('\Cake\Event\Event'), - $this->isInstanceOf('\Cake\ORM\Query'), - [], - false - ); - - $listener2 = $this->getMock('stdClass', ['__invoke']); - $table->eventManager()->attach($listener2, 'Model.beforeFind'); - $listener2->expects($this->once())->method('__invoke') - ->with( - $this->isInstanceOf('\Cake\Event\Event'), - $this->isInstanceOf('\Cake\ORM\Query'), - [], - false - ); - - $association->attachTo($query); - } - -/** - * Tests that attaching an association to a query will trigger beforeFind - * for the target table - * - * @return void - */ - public function testAttachToBeforeFindExtraOptions() { - $query = $this->getMock('\Cake\ORM\Query', ['join', 'select'], [null, null]); - $config = [ - 'sourceTable' => $this->article, - 'targetTable' => $this->tag, - ]; - $table = TableRegistry::get('ArticlesTags'); - $association = new BelongsToMany('Tags', $config); - $listener = $this->getMock('stdClass', ['__invoke']); - $this->tag->eventManager()->attach($listener, 'Model.beforeFind'); - $opts = ['something' => 'more']; - $listener->expects($this->once())->method('__invoke') - ->with( - $this->isInstanceOf('\Cake\Event\Event'), - $this->isInstanceOf('\Cake\ORM\Query'), - $opts, - false - ); - - $listener2 = $this->getMock('stdClass', ['__invoke']); - $table->eventManager()->attach($listener2, 'Model.beforeFind'); - $listener2->expects($this->once())->method('__invoke') - ->with( - $this->isInstanceOf('\Cake\Event\Event'), - $this->isInstanceOf('\Cake\ORM\Query'), - [], - false - ); - - $association->attachTo($query, ['queryBuilder' => function($q) { - return $q->applyOptions(['something' => 'more']); - }]); - } - } diff --git a/tests/TestCase/ORM/Association/BelongsToTest.php b/tests/TestCase/ORM/Association/BelongsToTest.php index 57becd34dc7..a5a8c226d70 100644 --- a/tests/TestCase/ORM/Association/BelongsToTest.php +++ b/tests/TestCase/ORM/Association/BelongsToTest.php @@ -130,40 +130,6 @@ public function testAttachTo() { $association->attachTo($query); } -/** - * Tests that default config defined in the association can be overridden - * - * @return void - */ - public function testAttachToConfigOverride() { - $query = $this->getMock('\Cake\ORM\Query', ['join', 'select'], [null, null]); - $config = [ - 'foreignKey' => 'company_id', - 'sourceTable' => $this->client, - 'conditions' => ['Companies.is_active' => true] - ]; - $association = new BelongsTo('Companies', $config); - $query->expects($this->once())->method('join')->with([ - 'Companies' => [ - 'conditions' => new QueryExpression([ - 'Companies.is_active' => false - ], $this->companiesTypeMap), - 'type' => 'LEFT', - 'table' => 'companies', - ] - ]); - $query->expects($this->once())->method('select')->with([ - 'Companies__company_name' => 'Companies.company_name' - ]); - - $override = [ - 'conditions' => ['Companies.is_active' => false], - 'foreignKey' => false, - 'fields' => ['company_name'] - ]; - $association->attachTo($query, $override); - } - /** * Tests that it is possible to avoid fields inclusion for the associated table * @@ -192,43 +158,6 @@ public function testAttachToNoFields() { $association->attachTo($query, ['includeFields' => false]); } -/** - * Tests that by passing a query builder function it is possible to add fields and - * conditions to an association - * - * @return void - */ - public function testAttachToWithQueryBuilder() { - $query = $this->getMock('\Cake\ORM\Query', ['join', 'select'], [null, null]); - $config = [ - 'sourceTable' => $this->client, - 'targetTable' => $this->company, - 'conditions' => ['Companies.is_active' => true] - ]; - $association = new BelongsTo('Companies', $config); - $field = new IdentifierExpression('Clients.company_id'); - $query->expects($this->once())->method('join')->with([ - 'Companies' => [ - 'conditions' => new QueryExpression([ - 'a' => 1, - 'Companies.is_active' => true, - ['Companies.id' => $field] - ], $this->companiesTypeMap), - 'type' => 'LEFT', - 'table' => 'companies', - ] - ]); - $query->expects($this->once())->method('select') - ->with([ - 'Companies__a' => 'Companies.a', - 'Companies__b' => 'Companies.b' - ]); - $builder = function($q) { - return $q->select(['a', 'b'])->where(['a' => 1]); - }; - $association->attachTo($query, ['queryBuilder' => $builder]); - } - /** * Tests that by passing the matching option to `attachTo` the association * is joinned using `INNER` diff --git a/tests/TestCase/ORM/Association/HasManyTest.php b/tests/TestCase/ORM/Association/HasManyTest.php index c2aee1314ff..51186e3f479 100644 --- a/tests/TestCase/ORM/Association/HasManyTest.php +++ b/tests/TestCase/ORM/Association/HasManyTest.php @@ -469,193 +469,6 @@ public function testEagerLoaderMultipleKeys() { $this->assertEquals($row, $result); } -/** - * Tests that the correct join and fields are attached to a query depending on - * the association config - * - * @return void - */ - public function testAttachTo() { - $query = $this->getMock('\Cake\ORM\Query', ['join', 'select'], [null, null]); - $config = [ - 'sourceTable' => $this->author, - 'targetTable' => $this->article, - 'conditions' => ['Articles.is_active' => true] - ]; - - $field = new IdentifierExpression('Articles.author_id'); - $association = new HasMany('Articles', $config); - $query->expects($this->once())->method('join')->with([ - 'Articles' => [ - 'conditions' => new QueryExpression([ - 'Articles.is_active' => true, - ['Authors.id' => $field] - ], $this->articlesTypeMap), - 'type' => 'INNER', - 'table' => 'articles' - ] - ]); - $query->expects($this->once())->method('select')->with([ - 'Articles__id' => 'Articles.id', - 'Articles__title' => 'Articles.title', - 'Articles__author_id' => 'Articles.author_id' - ]); - $association->attachTo($query); - } - -/** - * Tests that default config defined in the association can be overridden - * - * @return void - */ - public function testAttachToConfigOverride() { - $query = $this->getMock('\Cake\ORM\Query', ['join', 'select'], [null, null]); - $config = [ - 'sourceTable' => $this->author, - 'targetTable' => $this->article, - 'conditions' => ['Articles.is_active' => true] - ]; - $association = new HasMany('Articles', $config); - $query->expects($this->once())->method('join')->with([ - 'Articles' => [ - 'conditions' => new QueryExpression([ - 'Articles.is_active' => false - ], $this->articlesTypeMap), - 'type' => 'INNER', - 'table' => 'articles' - ] - ]); - $query->expects($this->once())->method('select')->with([ - 'Articles__title' => 'Articles.title' - ]); - - $override = [ - 'conditions' => ['Articles.is_active' => false], - 'foreignKey' => false, - 'fields' => ['title'] - ]; - $association->attachTo($query, $override); - } - -/** - * Tests that it is possible to avoid fields inclusion for the associated table - * - * @return void - */ - public function testAttachToNoFields() { - $query = $this->getMock('\Cake\ORM\Query', ['join', 'select'], [null, null]); - $config = [ - 'sourceTable' => $this->author, - 'targetTable' => $this->article, - 'conditions' => ['Articles.is_active' => true] - ]; - $field = new IdentifierExpression('Articles.author_id'); - $association = new HasMany('Articles', $config); - $query->expects($this->once())->method('join')->with([ - 'Articles' => [ - 'conditions' => new QueryExpression([ - 'Articles.is_active' => true, - ['Authors.id' => $field] - ], $this->articlesTypeMap), - 'type' => 'INNER', - 'table' => 'articles' - ] - ]); - $query->expects($this->never())->method('select'); - $association->attachTo($query, ['includeFields' => false]); - } - -/** - * Tests that using hasMany with a table having a multi column primary - * key will work if the foreign key is passed - * - * @return void - */ - public function testAttachToMultiPrimaryKey() { - $query = $this->getMock('\Cake\ORM\Query', ['join', 'select'], [null, null]); - $this->author->primaryKey(['id', 'site_id']); - $config = [ - 'sourceTable' => $this->author, - 'targetTable' => $this->article, - 'conditions' => ['Articles.is_active' => true], - 'foreignKey' => ['author_id', 'author_site_id'] - ]; - $field1 = new IdentifierExpression('Articles.author_id'); - $field2 = new IdentifierExpression('Articles.author_site_id'); - $association = new HasMany('Articles', $config); - $query->expects($this->once())->method('join')->with([ - 'Articles' => [ - 'conditions' => new QueryExpression([ - 'Articles.is_active' => true, - ['Authors.id' => $field1, 'Authors.site_id' => $field2] - ], $this->articlesTypeMap), - 'type' => 'INNER', - 'table' => 'articles' - ] - ]); - $query->expects($this->never())->method('select'); - $association->attachTo($query, ['includeFields' => false]); - } - -/** - * Tests that using hasMany with a table having a multi column primary - * key will work if the foreign key is passed - * - * @expectedException \RuntimeException - * @expectedExceptionMessage Cannot match provided foreignKey for "Articles", got "(author_id)" but expected foreign key for "(id, site_id) - * @return void - */ - public function testAttachToMultiPrimaryKeyMistmatch() { - $query = $this->getMock('\Cake\ORM\Query', ['join', 'select'], [null, null]); - $this->author->primaryKey(['id', 'site_id']); - $config = [ - 'sourceTable' => $this->author, - 'targetTable' => $this->article, - 'conditions' => ['Articles.is_active' => true], - 'foreignKey' => 'author_id' - ]; - $field1 = new IdentifierExpression('Articles.author_id'); - $field2 = new IdentifierExpression('Articles.author_site_id'); - $association = new HasMany('Articles', $config); - $association->attachTo($query, ['includeFields' => false]); - } - -/** - * Tests that by supplying a query builder function, it is possible to add fields - * and conditions to an association - * - * @return void - */ - public function testAttachToWithQueryBuilder() { - $query = $this->getMock('\Cake\ORM\Query', ['join', 'select'], [null, null]); - $config = [ - 'sourceTable' => $this->author, - 'targetTable' => $this->article, - 'conditions' => ['Articles.is_active' => true] - ]; - $field = new IdentifierExpression('Articles.author_id'); - $association = new HasMany('Articles', $config); - $query->expects($this->once())->method('join')->with([ - 'Articles' => [ - 'conditions' => new QueryExpression([ - 'a' => 1, - 'Articles.is_active' => true, - ['Authors.id' => $field], - ], $this->articlesTypeMap), - 'type' => 'INNER', - 'table' => 'articles' - ] - ]); - $query->expects($this->once())->method('select') - ->with([ - 'Articles__a' => 'Articles.a', - 'Articles__b' => 'Articles.b' - ]); - $builder = function($q) { - return $q->select(['a', 'b'])->where(['a' => 1]); - }; - $association->attachTo($query, ['queryBuilder' => $builder]); - } /** * Test cascading deletes. @@ -790,59 +603,4 @@ public function testPropertyNoPlugin() { $this->assertEquals('addresses', $association->property()); } -/** - * Tests that attaching an association to a query will trigger beforeFind - * for the target table - * - * @return void - */ - public function testAttachToBeforeFind() { - $query = $this->getMock('\Cake\ORM\Query', ['join', 'select'], [null, null]); - $config = [ - 'sourceTable' => $this->author, - 'targetTable' => $this->article, - ]; - - $listener = $this->getMock('stdClass', ['__invoke']); - $association = new HasMany('Articles', $config); - $this->article->eventManager()->attach($listener, 'Model.beforeFind'); - $listener->expects($this->once())->method('__invoke') - ->with( - $this->isInstanceOf('\Cake\Event\Event'), - $this->isInstanceOf('\Cake\ORM\Query'), - [], - false - ); - $association->attachTo($query); - } - -/** - * Tests that attaching an association to a query will trigger beforeFind - * for the target table - * - * @return void - */ - public function testAttachToBeforeFindExtraOptions() { - $query = $this->getMock('\Cake\ORM\Query', ['join', 'select'], [null, null]); - $config = [ - 'sourceTable' => $this->author, - 'targetTable' => $this->article, - ]; - - $listener = $this->getMock('stdClass', ['__invoke']); - $association = new HasMany('Articles', $config); - $this->article->eventManager()->attach($listener, 'Model.beforeFind'); - $opts = ['something' => 'more']; - $listener->expects($this->once())->method('__invoke') - ->with( - $this->isInstanceOf('\Cake\Event\Event'), - $this->isInstanceOf('\Cake\ORM\Query'), - $opts, - false - ); - $association->attachTo($query, ['queryBuilder' => function($q) { - return $q->applyOptions(['something' => 'more']); - }]); - } - } diff --git a/tests/TestCase/ORM/Association/HasOneTest.php b/tests/TestCase/ORM/Association/HasOneTest.php index bb03ea1effe..60c7c26a409 100644 --- a/tests/TestCase/ORM/Association/HasOneTest.php +++ b/tests/TestCase/ORM/Association/HasOneTest.php @@ -119,41 +119,6 @@ public function testAttachTo() { $association->attachTo($query); } -/** - * Tests that default config defined in the association can be overridden - * - * @return void - */ - public function testAttachToConfigOverride() { - $query = $this->getMock('\Cake\ORM\Query', ['join', 'select'], [null, null]); - $config = [ - 'foreignKey' => 'user_id', - 'sourceTable' => $this->user, - 'targetTable' => $this->profile, - 'conditions' => ['Profiles.is_active' => true] - ]; - $association = new HasOne('Profiles', $config); - $query->expects($this->once())->method('join')->with([ - 'Profiles' => [ - 'conditions' => new QueryExpression([ - 'Profiles.is_active' => false - ], $this->profilesTypeMap), - 'type' => 'LEFT', - 'table' => 'profiles' - ] - ]); - $query->expects($this->once())->method('select')->with([ - 'Profiles__first_name' => 'Profiles.first_name' - ]); - - $override = [ - 'conditions' => ['Profiles.is_active' => false], - 'foreignKey' => false, - 'fields' => ['first_name'] - ]; - $association->attachTo($query, $override); - } - /** * Tests that it is possible to avoid fields inclusion for the associated table * @@ -182,43 +147,6 @@ public function testAttachToNoFields() { $association->attachTo($query, ['includeFields' => false]); } -/** - * Tests that by supplying a query builder function, it is possible to add fields - * and conditions to an association - * - * @return void - */ - public function testAttachToWithQueryBuilder() { - $query = $this->getMock('\Cake\ORM\Query', ['join', 'select'], [null, null]); - $config = [ - 'sourceTable' => $this->user, - 'targetTable' => $this->profile, - 'conditions' => ['Profiles.is_active' => true] - ]; - $association = new HasOne('Profiles', $config); - $field = new IdentifierExpression('Profiles.user_id'); - $query->expects($this->once())->method('join')->with([ - 'Profiles' => [ - 'conditions' => new QueryExpression([ - 'a' => 1, - 'Profiles.is_active' => true, - ['Users.id' => $field], - ], $this->profilesTypeMap), - 'type' => 'LEFT', - 'table' => 'profiles' - ] - ]); - $query->expects($this->once())->method('select') - ->with([ - 'Profiles__a' => 'Profiles.a', - 'Profiles__b' => 'Profiles.b' - ]); - $builder = function($q) { - return $q->select(['a', 'b'])->where(['a' => 1]); - }; - $association->attachTo($query, ['queryBuilder' => $builder]); - } - /** * Tests that using hasOne with a table having a multi column primary * key will work if the foreign key is passed