/** * Returns query with applied filter * * @param \Cake\ORM\Query $query Query. * @param string $field Field name. * @param string $value Field value. * @param array $data Filters values. * @return \Cake\ORM\Query */ protected function _buildQuery(Query $query, $field, $value, array $data = []) { // @todo bind to parent Articles.id using initialization parameter $alias = $query->repository()->alias(); $tags = TableRegistry::get('ArticlesTags')->find('all')->matching('Tags', function ($q) use($value, $alias) { return $q->where(['Tags.name' => $value]); })->where(["ArticlesTags.article_id = {$alias}.id"]); return $query->where([new UnaryExpression('EXISTS', $tags)]); }
/** * Tests that HasMany associations are correctly eager loaded and results * correctly nested when multiple foreignKeys are used * * @dataProvider strategiesProvider * @return void */ public function testHasManyEager($strategy) { $table = TableRegistry::get('SiteAuthors'); $table->hasMany('SiteArticles', ['propertyName' => 'articles', 'strategy' => $strategy, 'sort' => ['SiteArticles.id' => 'asc'], 'foreignKey' => ['author_id', 'site_id']]); $query = new Query($this->connection, $table); $results = $query->select()->contain('SiteArticles')->hydrate(false)->toArray(); $expected = [['id' => 1, 'name' => 'mark', 'site_id' => 1, 'articles' => [['id' => 1, 'title' => 'First Article', 'body' => 'First Article Body', 'author_id' => 1, 'site_id' => 1]]], ['id' => 2, 'name' => 'juan', 'site_id' => 2, 'articles' => []], ['id' => 3, 'name' => 'jose', 'site_id' => 2, 'articles' => [['id' => 2, 'title' => 'Second Article', 'body' => 'Second Article Body', 'author_id' => 3, 'site_id' => 2]]], ['id' => 4, 'name' => 'andy', 'site_id' => 1, 'articles' => []]]; $this->assertEquals($expected, $results); $results = $query->repository($table)->select()->contain(['SiteArticles' => ['conditions' => ['id' => 2]]])->hydrate(false)->toArray(); $expected[0]['articles'] = []; $this->assertEquals($expected, $results); $this->assertEquals($table->association('SiteArticles')->strategy(), $strategy); }
/** * Get CakePHP property * * @param string $dataName Column data name * * @throws Exception * @return array|string */ protected function getProperty($dataName) { $dataName = explode('.', trim($dataName)); if (count($dataName) != 2) { throw new Exception('You are set invalid date.'); } $tableAlias = $dataName[0]; $colName = $dataName[1]; if ($this->query->repository()->alias() == $tableAlias) { return $colName; } elseif (array_key_exists($tableAlias, $this->query->contain())) { return ['propertyPath' => $this->query->eagerLoader()->normalized($this->query->repository())[$tableAlias]['propertyPath'], 'field' => $colName]; } }
/** * Constructor * * @param \Cake\ORM\Query $query Query from where results come * @param \Cake\Database\StatementInterface $statement */ public function __construct($query, $statement) { $repository = $query->repository(); $this->_query = $query; $this->_statement = $statement; $this->_defaultTable = $this->_query->repository(); $this->_calculateAssociationMap(); $this->_hydrate = $this->_query->hydrate(); $this->_entityClass = $repository->entityClass(); $this->_useBuffering = $query->bufferResults(); if ($statement) { $this->count(); } }
public function beforeFind(Event $event, Query $query, $options, $primary) { $config = $this->config(); $tableAlias = $query->repository()->alias(); $founded = false; if ($where = $query->clause('where')) { $where->iterateParts(function ($w) use($config, $tableAlias, &$founded) { $field = is_object($w) ? $w->getField() : $w; if ($field == $tableAlias . '.' . $config['field'] || $field == $config['field']) { $founded = true; } return $w; }); } if (!$founded) { $query->where(['deleted' => 0]); } }
/** * Constructor * * @param \Cake\ORM\Query $query Query from where results come * @param \Cake\Database\StatementInterface $statement The statement to fetch from */ public function __construct($query, $statement) { $repository = $query->repository(); $this->_query = $query; $this->_statement = $statement; $this->_driver = $driver = $this->_query->connection()->driver(); $this->_defaultTable = $this->_query->repository(); $this->_calculateAssociationMap(); $this->_hydrate = $this->_query->hydrate(); $this->_entityClass = $repository->entityClass(); $this->_useBuffering = $query->bufferResults(); $this->_defaultAlias = $this->_defaultTable->alias(); $this->_calculateColumnMap(); $this->_calculateTypeMap(); if ($this->_useBuffering) { $count = $this->count(); $this->_results = new SplFixedArray($count); } }
/** * Decorates the passed statement object in order to inject data from associations * that cannot be joined directly. * * @param \Cake\ORM\Query $query The query for which to eager load external * associations * @param \Cake\Database\StatementInterface $statement The statement created after executing the $query * @return CallbackStatement statement modified statement with extra loaders */ public function loadExternal($query, $statement) { $external = $this->externalAssociations($query->repository()); if (empty($external)) { return $statement; } $driver = $query->connection()->driver(); list($collected, $statement) = $this->_collectKeys($external, $query, $statement); foreach ($external as $meta) { $contain = $meta->associations(); $instance = $meta->instance(); $config = $meta->config(); $alias = $instance->source()->alias(); $path = $meta->aliasPath(); $requiresKeys = $instance->requiresKeys($config); if ($requiresKeys && empty($collected[$path][$alias])) { continue; } $keys = isset($collected[$path][$alias]) ? $collected[$path][$alias] : null; $f = $instance->eagerLoader($config + ['query' => $query, 'contain' => $contain, 'keys' => $keys, 'nestKey' => $meta->aliasPath()]); $statement = new CallbackStatement($statement, $driver, $f); } return $statement; }
/** * Tests that it is possible to call matching and contain on the same * association. * * @return void */ public function testMatchingWithContain() { $query = new Query($this->connection, $this->table); $table = TableRegistry::get('authors'); $table->hasMany('articles'); TableRegistry::get('articles')->belongsToMany('tags'); $result = $query->repository($table)->select()->matching('articles.tags', function ($q) { return $q->where(['tags.id' => 2]); })->contain('articles')->first(); $this->assertEquals(1, $result->id); $this->assertCount(2, $result->articles); $this->assertEquals(2, $result->_matchingData['tags']->id); }
/** * Builds a query to be used as a condition for filtering records in the * target table, it is constructed by cloning the original query that was used * to load records in the source table. * * @param \Cake\ORM\Query $query the original query used to load source records * @return \Cake\ORM\Query */ protected function _buildSubquery($query) { $filterQuery = clone $query; $filterQuery->autoFields(false); $filterQuery->mapReduce(null, null, true); $filterQuery->formatResults(null, true); $filterQuery->contain([], true); if (!$filterQuery->clause('limit')) { $filterQuery->limit(null); $filterQuery->order([], true); $filterQuery->offset(null); } $keys = (array) $query->repository()->primaryKey(); if ($this->type() === $this::MANY_TO_ONE) { $keys = (array) $this->foreignKey(); } $fields = $query->aliasFields($keys, $this->source()->alias()); $filterQuery->select($fields, true)->group(array_values($fields)); return $filterQuery; }
/** * testbeforePaginate * * @return void */ public function testbeforePaginate() { $listener = $this->getMockBuilder('\\Crud\\Listener\\RelatedModelsListener')->disableOriginalConstructor()->setMethods(['models'])->getMock(); $table = $this->getMockBuilder('\\Cake\\ORM\\Table')->disableOriginalConstructor()->setMethods(['associations', 'association'])->getMock(); $listener->expects($this->once())->method('models')->will($this->returnValue(['Users' => 'manyToOne'])); $db = $this->getMockBuilder('\\Cake\\Database\\Connection')->disableOriginalConstructor()->getMock(); $query = new Query($db, null); $query->repository($table); $subject = new Subject(['query' => $query]); $event = new Event('beforePaginate', $subject); $listener->beforePaginate($event); $result = $event->subject()->query->contain(); $this->assertEquals(['Users' => []], $result); }
/** * Tests that it is possible to filter by deep associations * * @return void */ public function testMatchingDotNotation() { $query = new Query($this->connection, $this->table); $table = TableRegistry::get('authors'); TableRegistry::get('articles'); $table->hasMany('articles'); TableRegistry::get('articles')->belongsToMany('tags'); $results = $query->repository($table)->select()->hydrate(false)->matching('articles.tags', function ($q) { return $q->where(['tags.id' => 2]); })->toArray(); $expected = [['id' => 1, 'name' => 'mariano', 'articles' => ['id' => 1, 'title' => 'First Article', 'body' => 'First Article Body', 'author_id' => 1, 'published' => 'Y', 'tags' => ['id' => 2, 'name' => 'tag2', '_joinData' => ['article_id' => 1, 'tag_id' => 2]]]]]; $this->assertEquals($expected, $results); }
/** * Builds a query to be used as a condition for filtering records in the * target table, it is constructed by cloning the original query that was used * to load records in the source table. * * @param \Cake\ORM\Query $query the original query used to load source records * @return \Cake\ORM\Query */ protected function _buildSubquery($query) { $filterQuery = clone $query; $filterQuery->limit(null); $filterQuery->order([], true); $filterQuery->contain([], true); $joins = $filterQuery->join(); foreach ($joins as $i => $join) { if (strtolower($join['type']) !== 'inner') { unset($joins[$i]); } } $keys = (array) $query->repository()->primaryKey(); if ($this->type() === $this::MANY_TO_ONE) { $keys = (array) $this->foreignKey(); } $filterQuery->join($joins, [], true); $fields = $query->aliasFields($keys); return $filterQuery->select($fields, true); }