$_value
$_value : mixed
The value to be used in the right hand side of the operation
This expression represents SQL fragments that are used for comparing one tuple to another, one tuple to a set of other tuples or one tuple to an expression
$_valueExpressions : array<mixed,\Cake\Database\ExpressionInterface>
A cached list of ExpressionInterface objects that were found in the value for this expression.
$_field : string|\Cake\Database\ExpressionInterface
The field name or expression to be used in the left hand side of the operator
__construct(string|array|\Cake\Database\ExpressionInterface $fields, array|\Cake\Database\ExpressionInterface $values, array $types = array(), string $conjunction = '=')
Constructor
| string|array|\Cake\Database\ExpressionInterface | $fields | the fields to use to form a tuple |
| array|\Cake\Database\ExpressionInterface | $values | the values to use to form a tuple |
| array | $types | the types names to use for casting each of the values, only one type per position in the value array in needed |
| string | $conjunction | the operator used for comparing field and value |
sql(\Cake\Database\ValueBinder $generator) : string
Convert the expression into a SQL fragment.
| \Cake\Database\ValueBinder | $generator | Placeholder generator object |
traverse(callable $callable) : void
Traverses the tree of expressions stored in this object, visiting first expressions in the left hand side and then the rest.
Callback function receives as its only argument an instance of an ExpressionInterface
| callable | $callable | The callable to apply to sub-expressions |
setField(string|\Cake\Database\ExpressionInterface $field) : void
Sets the field name
| string|\Cake\Database\ExpressionInterface | $field | The field to compare with. |
getField() : string|\Cake\Database\ExpressionInterface
Returns the field name
_stringExpression(\Cake\Database\ValueBinder $generator) : array
Returns a template and a placeholder for the value after registering it with the placeholder $generator
| \Cake\Database\ValueBinder | $generator | The value binder to use. |
First position containing the template and the second a placeholder
_bindValue(\Cake\Database\ValueBinder $generator, mixed $value, string $type) : string
Registers a value in the placeholder generator and returns the generated placeholder
| \Cake\Database\ValueBinder | $generator | The value binder |
| mixed | $value | The value to bind |
| string | $type | The type to use |
generated placeholder
_flattenValue(array|\Traversable $value, \Cake\Database\ValueBinder $generator, string|array|null $type = 'string') : string
Converts a traversable value into a set of placeholders generated by $generator and separated by `,`
| array|\Traversable | $value | the value to flatten |
| \Cake\Database\ValueBinder | $generator | The value binder to use |
| string|array|null | $type | the type to cast values to |
_castToExpression(mixed $value, string $type) : mixed
Conditionally converts the passed value to an ExpressionInterface object if the type class implements the ExpressionTypeInterface. Otherwise, returns the value unmodified.
| mixed | $value | The value to converto to ExpressionInterface |
| string | $type | The type name |
_stringifyValues(\Cake\Database\ValueBinder $generator) : string
Returns a string with the values as placeholders in a string to be used for the SQL version of this expression
| \Cake\Database\ValueBinder | $generator | The value binder to convert expressions with. |
<?php
/**
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
* @link https://cakephp.org CakePHP(tm) Project
* @since 3.0.0
* @license https://opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\Database\Expression;
use Cake\Database\ExpressionInterface;
use Cake\Database\ValueBinder;
/**
* This expression represents SQL fragments that are used for comparing one tuple
* to another, one tuple to a set of other tuples or one tuple to an expression
*/
class TupleComparison extends Comparison
{
/**
* Constructor
*
* @param string|array|\Cake\Database\ExpressionInterface $fields the fields to use to form a tuple
* @param array|\Cake\Database\ExpressionInterface $values the values to use to form a tuple
* @param array $types the types names to use for casting each of the values, only
* one type per position in the value array in needed
* @param string $conjunction the operator used for comparing field and value
*/
public function __construct($fields, $values, $types = [], $conjunction = '=')
{
parent::__construct($fields, $values, $types, $conjunction);
$this->_type = (array)$types;
}
/**
* Convert the expression into a SQL fragment.
*
* @param \Cake\Database\ValueBinder $generator Placeholder generator object
* @return string
*/
public function sql(ValueBinder $generator)
{
$template = '(%s) %s (%s)';
$fields = [];
$originalFields = $this->getField();
if (!is_array($originalFields)) {
$originalFields = [$originalFields];
}
foreach ($originalFields as $field) {
$fields[] = $field instanceof ExpressionInterface ? $field->sql($generator) : $field;
}
$values = $this->_stringifyValues($generator);
$field = implode(', ', $fields);
return sprintf($template, $field, $this->_operator, $values);
}
/**
* Returns a string with the values as placeholders in a string to be used
* for the SQL version of this expression
*
* @param \Cake\Database\ValueBinder $generator The value binder to convert expressions with.
* @return string
*/
protected function _stringifyValues($generator)
{
$values = [];
$parts = $this->getValue();
if ($parts instanceof ExpressionInterface) {
return $parts->sql($generator);
}
foreach ($parts as $i => $value) {
if ($value instanceof ExpressionInterface) {
$values[] = $value->sql($generator);
continue;
}
$type = $this->_type;
$multiType = is_array($type);
$isMulti = $this->isMulti();
$type = $multiType ? $type : str_replace('[]', '', $type);
$type = $type ?: null;
if ($isMulti) {
$bound = [];
foreach ($value as $k => $val) {
$valType = $multiType ? $type[$k] : $type;
$bound[] = $this->_bindValue($generator, $val, $valType);
}
$values[] = sprintf('(%s)', implode(',', $bound));
continue;
}
$valType = $multiType && isset($type[$i]) ? $type[$i] : $type;
$values[] = $this->_bindValue($generator, $value, $valType);
}
return implode(', ', $values);
}
/**
* Registers a value in the placeholder generator and returns the generated
* placeholder
*
* @param \Cake\Database\ValueBinder $generator The value binder
* @param mixed $value The value to bind
* @param string $type The type to use
* @return string generated placeholder
*/
protected function _bindValue($generator, $value, $type)
{
$placeholder = $generator->placeholder('tuple');
$generator->bind($placeholder, $value, $type);
return $placeholder;
}
/**
* Traverses the tree of expressions stored in this object, visiting first
* expressions in the left hand side and then the rest.
*
* Callback function receives as its only argument an instance of an ExpressionInterface
*
* @param callable $callable The callable to apply to sub-expressions
* @return void
*/
public function traverse(callable $callable)
{
foreach ($this->getField() as $field) {
$this->_traverseValue($field, $callable);
}
$value = $this->getValue();
if ($value instanceof ExpressionInterface) {
$callable($value);
$value->traverse($callable);
return;
}
foreach ($value as $i => $val) {
if ($this->isMulti()) {
foreach ($val as $v) {
$this->_traverseValue($v, $callable);
}
} else {
$this->_traverseValue($val, $callable);
}
}
}
/**
* Conditionally executes the callback for the passed value if
* it is an ExpressionInterface
*
* @param mixed $value The value to traverse
* @param callable $callable The callable to use when traversing
* @return void
*/
protected function _traverseValue($value, $callable)
{
if ($value instanceof ExpressionInterface) {
$callable($value);
$value->traverse($callable);
}
}
/**
* Determines if each of the values in this expressions is a tuple in
* itself
*
* @return bool
*/
public function isMulti()
{
return in_array(strtolower($this->_operator), ['in', 'not in']);
}
}