/**
  * Find By Distance using spherical cosine law
  *
  * @param \Cake\ORM\Query $query Query to modify
  * @param array $options Options for the query
  * @throws GeoDistanceInvalidArgumentException If parameters are missing or invalid
  * @return \Cake\ORM\Query
  */
 public function findByDistance(Query $query, array $options)
 {
     // set up parameters
     $this->_validateOptions($options);
     $latitude = $options['latitude'];
     $longitude = $options['longitude'];
     $radius = $options['radius'];
     if (isset($options['units']) && !empty($options['units'])) {
         $units = $options['units'];
     } else {
         $units = $this->_config['units'];
     }
     $earthRadius = $this->_getEarthRadius($units);
     // construct query
     $sphericalCosineSql = "(:earth_radius * ACOS(\n            COS(RADIANS(:latitude)) *\n            COS(RADIANS({$this->_config['latitudeColumn']})) *\n            COS( RADIANS({$this->_config['longitudeColumn']}) - RADIANS(:longitude) ) +\n            SIN(RADIANS(:latitude)) *\n            SIN(RADIANS({$this->_config['latitudeColumn']}))\n        ) )";
     $connection = $query->connection();
     if ($connection->driver() instanceof Mysql) {
         $distance = "ROUND({$sphericalCosineSql}, 3)";
     } elseif ($connection->driver() instanceof Postgres) {
         $distance = "ROUND( CAST({$sphericalCosineSql} AS numeric), 3)";
     }
     $queryOptions = ['fields' => ['distance' => $distance], 'order' => ['distance ASC'], 'conditions' => ["{$distance} <= :radius"]];
     $query->find('all', $queryOptions)->autoFields(true)->bind(':earth_radius', $earthRadius, 'integer')->bind(':latitude', $latitude, 'float')->bind(':longitude', $longitude, 'float')->bind(':radius', $radius, 'float');
     return $query;
 }
Exemple #2
0
 /**
  * Casts all values from a row brought from a table to the correct
  * PHP type.
  *
  * @param Table $table The table object
  * @param array $values The values to cast
  * @return array
  */
 protected function _castValues($table, $values)
 {
     $alias = $table->alias();
     $driver = $this->_query->connection()->driver();
     if (empty($this->types[$alias])) {
         $schema = $table->schema();
         foreach ($schema->columns() as $col) {
             $this->types[$alias][$col] = Type::build($schema->columnType($col));
         }
     }
     foreach ($values as $field => $value) {
         if (!isset($this->types[$alias][$field])) {
             continue;
         }
         $values[$field] = $this->types[$alias][$field]->toPHP($value, $driver);
     }
     return $values;
 }
 /**
  * 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);
     }
 }
 /**
  * Helper function used to return the keys from the query records that will be used
  * to eagerly load associations.
  *
  * @param array $external the list of external associations to be loaded
  * @param \Cake\ORM\Query $query The query from which the results where generated
  * @param BufferedStatement $statement The statement to work on
  * @return array
  */
 protected function _collectKeys($external, $query, $statement)
 {
     $collectKeys = [];
     foreach ($external as $meta) {
         $instance = $meta->instance();
         if (!$instance->requiresKeys($meta->config())) {
             continue;
         }
         $source = $instance->source();
         $keys = $instance->type() === Association::MANY_TO_ONE ? (array) $instance->foreignKey() : (array) $instance->bindingKey();
         $alias = $source->alias();
         $pkFields = [];
         foreach ($keys as $key) {
             $pkFields[] = key($query->aliasField($key, $alias));
         }
         $collectKeys[$meta->aliasPath()] = [$alias, $pkFields, count($pkFields) === 1];
     }
     if (empty($collectKeys)) {
         return [[], $statement];
     }
     if (!$statement instanceof BufferedStatement) {
         $statement = new BufferedStatement($statement, $query->connection()->driver());
     }
     return [$this->_groupKeys($statement, $collectKeys), $statement];
 }
 /**
  * Assertion method for select clause contents.
  *
  * @param array $expected Array of expected fields.
  * @param \Cake\ORM\Query $query The query to check.
  * @return void
  */
 protected function assertSelectClause($expected, $query)
 {
     if ($this->autoQuote) {
         $connection = $query->connection();
         foreach ($expected as $key => $value) {
             $expected[$connection->quoteIdentifier($key)] = $connection->quoteIdentifier($value);
             unset($expected[$key]);
         }
     }
     $this->assertEquals($expected, $query->clause('select'));
 }
Exemple #6
0
 /**
  * Gets the name of the class driver used by the given $query to access the DB.
  *
  * @param \Cake\ORM\Query $query The query to inspect
  * @return string Lowercased drive name. e.g. `mysql`
  */
 protected function _driverClass(Query $query)
 {
     $conn = $query->connection(null);
     list(, $driverClass) = namespaceSplit(strtolower(get_class($conn->driver())));
     return $driverClass;
 }
 /**
  * Checks that the fetching query either has auto fields on or
  * has the foreignKey fields selected.
  * If the required fields are missing, throws an exception.
  *
  * @param \Cake\ORM\Query $fetchQuery The association fetching query
  * @param array $key The foreign key fields to check
  * @return void
  * @throws InvalidArgumentException
  */
 protected function _assertFieldsPresent($fetchQuery, $key)
 {
     $select = $fetchQuery->aliasFields($fetchQuery->clause('select'));
     if (empty($select)) {
         return;
     }
     $missingKey = function ($fieldList, $key) {
         foreach ($key as $keyField) {
             if (!in_array($keyField, $fieldList, true)) {
                 return true;
             }
         }
         return false;
     };
     $missingFields = $missingKey($select, $key);
     if ($missingFields) {
         $driver = $fetchQuery->connection()->driver();
         $quoted = array_map([$driver, 'quoteIdentifier'], $key);
         $missingFields = $missingKey($select, $quoted);
     }
     if ($missingFields) {
         throw new InvalidArgumentException(sprintf('You are required to select the "%s" field(s)', implode(', ', (array) $key)));
     }
 }