/** * Custom finder for distance. * * Options: * - lat (required) * - lng (required) * - tableName * - distance * - sort * * @param \Cake\ORM\Query $query Query. * @param array $options Array of options as described above * @return \Cake\ORM\Query */ public function findDistance(Query $query, array $options) { $options += ['tableName' => null, 'sort' => true]; $sql = $this->distanceExpr($options['lat'], $options['lng'], null, null, $options['tableName']); if ($query->autoFields() === null) { $query->autoFields(true); } $query->select(['distance' => $query->newExpr($sql)]); if (isset($options['distance'])) { // Some SQL versions cannot reuse the select() distance field, so we better reuse the $sql snippet $query->where(function ($exp) use($sql, $options) { return $exp->lt($sql, $options['distance']); }); } if ($options['sort']) { $sort = $options['sort'] === true ? 'ASC' : $options['sort']; $query->order(['distance' => $sort]); } return $query; }
/** * Helper function used to conditionally append fields to the select clause of * a query from the fields found in another query object. * * @param \Cake\ORM\Query $query the query that will get the fields appended to * @param \Cake\ORM\Query $surrogate the query having the fields to be copied from * @param array $options options passed to the method `attachTo` * @return void */ protected function _appendFields($query, $surrogate, $options) { $fields = $surrogate->clause('select') ?: $options['fields']; $target = $this->_targetTable; $autoFields = $surrogate->autoFields(); if ($query->eagerLoader()->autoFields() === false) { return; } if (empty($fields) && !$autoFields) { if ($options['includeFields'] && ($fields === null || $fields !== false)) { $fields = $target->schema()->columns(); } } if ($autoFields === true) { $fields = array_merge((array) $fields, $target->schema()->columns()); } if (!empty($fields)) { $query->select($query->aliasFields($fields, $target->alias())); } }
/** * Callback method that listens to the `beforeFind` event in the bound * table. It modifies the passed query by eager loading the translated fields * and adding a formatter to copy the values into the main table records. * * @param \Cake\Event\Event $event The beforeFind event that was fired. * @param \Cake\ORM\Query $query Query * @param \ArrayObject $options The options for the query * @return void */ public function beforeFind(Event $event, Query $query, $options) { $locale = $this->locale(); if ($locale === $this->config('defaultLocale')) { return; } $conditions = function ($field, $locale, $query, $select) { return function ($q) use($field, $locale, $query, $select) { $q->where([$q->repository()->aliasField('locale') => $locale]); if ($query->autoFields() || in_array($field, $select, true) || in_array($this->_table->aliasField($field), $select, true)) { $q->select(['id', 'content']); } return $q; }; }; $contain = []; $fields = $this->_config['fields']; $alias = $this->_table->alias(); $select = $query->clause('select'); $changeFilter = isset($options['filterByCurrentLocale']) && $options['filterByCurrentLocale'] !== $this->_config['onlyTranslated']; foreach ($fields as $field) { $name = $alias . '_' . $field . '_translation'; $contain[$name]['queryBuilder'] = $conditions($field, $locale, $query, $select); if ($changeFilter) { $filter = $options['filterByCurrentLocale'] ? 'INNER' : 'LEFT'; $contain[$name]['joinType'] = $filter; } } $query->contain($contain); $query->formatResults(function ($results) use($locale) { return $this->_rowMapper($results, $locale); }, $query::PREPEND); }