CakePHP 3.0 -> Entre la condición de búsqueda

¿Es posible hacer un “ENTRE? ¿Y?” donde la condición LIKE en cakephp 2.5? En cakephp 2.5 escribo algo así como

'conditions' => ['start_date BETWEEN ? AND ?' => ['2014-01-01', '2014-12-32']] 

¿Cómo puedo migrar eso?

Además, escribiría algo así como

 'conditions' => [ '? BETWEEN start_date AND end_date'] => '2014-03-31'] 

Expresiones

Entre las expresiones se admiten listas para usar, sin embargo, solo admiten el primer caso sin manipulación adicional:

 $Query = $Table ->find() ->where(function($exp) { return $exp->between('start_date', '2014-01-01', '2014-12-32', 'date'); }); 

Si quisieras manejar el segundo caso a través del método between, entonces tendrías que pasar todos los valores como expresiones, que pueden ir mal, ya que no estarán sujetas a la vinculación de escapes / parámetros en ese caso, ‘ Tengo que hacer eso por tu cuenta (¡que es todo menos recomendable! Mira las notas de seguridad en el manual para PDO::quote() ), algo como:

 use Cake\Database\Expression\IdentifierExpression; use Cake\Database\Expression\QueryExpression; use Cake\ORM\Query; // ... $Query = $Table ->find() ->where(function(QueryExpression $exp, Query $query) { return $exp->between( $query->newExpr( $query->connection()->driver()->quote( '2014-03-31', \PDO::PARAM_STR ) ), new IdentifierExpression('start_date'), new IdentifierExpression('end_date') ); }); 

Eso podría parecer un poco inconveniente para una expresión SQL básica tan compatible con todos los dialectos SQL con los que CakePHP se envía, por lo que puede que tenga una razón para usar value bindig en su lugar.

Sin embargo, debe tenerse en cuenta que las expresiones son generalmente la mejor opción cuando se trata del soporte de dialectos cruzados, ya que pueden transformarse (más o menos) fácilmente en tiempo de comstackción, consulte las implementaciones de SqlDialectTrait::_expressionTranslators() . Además, las expresiones generalmente admiten el uso de citas de identificador automático.

Valor vinculante

A través del enlace de valor manual puede crear casi cualquier cosa que desee. Sin embargo, debe tenerse en cuenta que, siempre que sea posible, debe usar expresiones en su lugar, ya que son más fáciles de portar, lo que sucede de manera predeterminada para algunas expresiones.

 $Query = $Table ->find() ->where([ 'start_date BETWEEN :start AND :end' ]) ->bind(':start', '2014-01-01', 'date') ->bind(':end', '2014-12-31', 'date'); 

De esta forma, el segundo caso también se puede resolver muy fácilmente, como:

 $Query = $Table ->find() ->where([ ':date BETWEEN start_date AND end_date' ]) ->bind(':date', '2014-03-31', 'date'); 

Una mezcla de ambos (enfoque más seguro y más compatible)

También es posible mezclar ambos, es decir, usar una expresión que haga uso de enlaces personalizados, algo parecido a esto:

 use Cake\Database\Expression\IdentifierExpression; use Cake\Database\Expression\QueryExpression; use Cake\ORM\Query; // ... $Query = $Table ->find() ->where(function(QueryExpression $exp, Query $query) { return $exp->between( $query->newExpr(':date'), new IdentifierExpression('start_date'), new IdentifierExpression('end_date') ); }) ->bind(':date', '2014-03-31', 'date'); 

De esta forma, puede manejar el segundo caso utilizando expresiones posiblemente portátiles, y no tiene que preocuparse de citar / escanear datos de entrada e identificadores manualmente.

Ver también

  • Libro de cocina> Acceso a la base de datos y ORM> Query Builder> Condiciones avanzadas
  • API> \ Cake \ Database \ Query :: bind ()

Actualmente parece que solo hay dos opciones. El núcleo ahora es compatible con esto, solo se conserva como referencia.

Valor vinculante (a través del generador de consultas de la base de datos)

Por ahora, el generador de consultas ORM ( Cake\ORM\Query ), el que se está recuperando al invocar, por ejemplo, find() en un objeto de tabla, no admite el enlace de valores.

https://github.com/cakephp/cakephp/issues/4926

Por lo tanto, para poder utilizar enlaces, debe usar el generador de consultas de base de datos subyacente ( Cake\Database\Query ), que puede, por ejemplo, recuperarse a través de Connection::newQuery() .

Aquí hay un ejemplo:

 $conn = ConnectionManager::get('default'); $Query = $conn->newQuery(); $Query ->select('*') ->from('table_name') ->where([ 'start_date BETWEEN :start AND :end' ]) ->bind(':start', new \DateTime('2014-01-01'), 'date') ->bind(':end', new \DateTime('2014-12-31'), 'date'); debug($Query->execute()->fetchAll()); 

Esto daría lugar a una consulta similar a esta

 SELECT * FROM table_name WHERE start_date BETWEEN '2014-01-01' AND '2014-12-31' 

Una clase de expresión personalizada

Otra opción sería una clase de expresión personalizada que genere fragmentos de SQL apropiados. Aquí hay un ejemplo.

Los nombres de columna deben estar incluidos en objetos de expresión de identificador para que se puedan citar automáticamente (en caso de que se habilite la cita automática), la syntax de matriz clave> valor es para valores de enlace, donde la clave de matriz es el valor real y el valor de matriz el tipo de datos.

Tenga en cuenta que no es seguro pasar directamente la entrada del usuario para los nombres de las columnas, ya que no se están escapando. ¡Use una lista blanca o similar para asegurarse de que el nombre de la columna sea seguro de usar!

Campo entre valores

 use App\Database\Expression\BetweenComparison; use Cake\Database\Expression\IdentifierExpression; // ... $between = new BetweenComparison( new IdentifierExpression('created'), ['2014-01-01' => 'date'], ['2014-12-31' => 'date'] ); $TableName = TableRegistry::get('TableName'); $Query = $TableName ->find() ->where($between); debug($Query->execute()->fetchAll()); 

Esto generaría una consulta similar a la de arriba.

Valor entre campos

 use App\Database\Expression\BetweenComparison; use Cake\Database\Expression\IdentifierExpression; // ... $between = new BetweenComparison( ['2014-03-31' => 'date'], new IdentifierExpression('start_date'), new IdentifierExpression('end_date') ); $TableName = TableRegistry::get('TableName'); $Query = $TableName ->find() ->where($between); debug($Query->execute()->fetchAll()); 

Esto, por otro lado, daría lugar a una consulta similar a esta

 SELECT * FROM table_name WHERE '2014-03-31' BETWEEN start_date AND end_date 

La clase de expresión

 namespace App\Database\Expression; use Cake\Database\ExpressionInterface; use Cake\Database\ValueBinder; class BetweenComparison implements ExpressionInterface { protected $_field; protected $_valueA; protected $_valueB; public function __construct($field, $valueA, $valueB) { $this->_field = $field; $this->_valueA = $valueA; $this->_valueB = $valueB; } public function sql(ValueBinder $generator) { $field = $this->_compilePart($this->_field, $generator); $valueA = $this->_compilePart($this->_valueA, $generator); $valueB = $this->_compilePart($this->_valueB, $generator); return sprintf('%s BETWEEN %s AND %s', $field, $valueA, $valueB); } public function traverse(callable $callable) { $this->_traversePart($this->_field, $callable); $this->_traversePart($this->_valueA, $callable); $this->_traversePart($this->_valueB, $callable); } protected function _bindValue($value, $generator, $type) { $placeholder = $generator->placeholder('c'); $generator->bind($placeholder, $value, $type); return $placeholder; } protected function _compilePart($value, $generator) { if ($value instanceof ExpressionInterface) { return $value->sql($generator); } else if(is_array($value)) { return $this->_bindValue(key($value), $generator, current($value)); } return $value; } protected function _traversePart($value, callable $callable) { if ($value instanceof ExpressionInterface) { $callable($value); $value->traverse($callable); } } } 

Puedes usar uno de los siguientes 2 métodos.

Método 1 :

 $start_date = '2014-01-01 00:00:00'; $end_date = '2014-12-31 23:59:59'; $query = $this->Table->find('all') ->where(function ($exp, $q) use($start_date,$end_date) { return $exp->between('start_date', $start_date, $end_date); }); $result = $query->toArray(); 

Método 2:

 $start_date = '2014-01-01 00:00:00'; $end_date = '2014-12-31 23:59:59'; $query = $this->Table->find('all') ->where([ 'start_date BETWEEN :start AND :end' ]) ->bind(':start', new \DateTime($start_date), 'datetime') ->bind(':end', new \DateTime($end_date), 'datetime'); $result = $query->toArray(); 

Los chicos de Helo pls usan esta consulta para obtener datos sobre la base del rango de valor

$ query = $ this-> Leads-> find (‘all’, array (‘condiciones’ => array (‘postcode BETWEEN’. $ postcodeFrom. ‘y’. $ postcodeTo. ”), ‘recursive’ => – 1)); debug ($ query); print_r ($ query-> toArray ());