Skip to content
Permalink
Browse files

Making Comparison correctly traverse expressions in array values

Started testing the type conversion to expressions
  • Loading branch information...
lorenzo committed Mar 21, 2016
1 parent 3158cf6 commit 98a526755344b5dfc17a038995f93b667474dbdc
@@ -15,6 +15,7 @@
namespace Cake\Database\Expression;
use Cake\Database\ExpressionInterface;
use Cake\Database\Type\TypeExpressionCasterTrait;
use Cake\Database\ValueBinder;
/**
@@ -25,6 +26,8 @@
class CaseExpression implements ExpressionInterface
{
use TypeExpressionCasterTrait;
/**
* A list of strings or other expression objects that represent the conditions of
* the case statement. For example one key of the array might look like "sum > :value"
@@ -53,6 +53,10 @@ class Comparison implements ExpressionInterface, FieldInterface
*/
protected $_operator;
protected $_isMultiple = false;
protected $_valueExpressions = [];
/**
* Constructor
*
@@ -80,10 +84,18 @@ public function __construct($field, $value, $type, $operator)
*/
public function setValue($value)
{
if (isset($this->_type)) {
$hasType = isset($this->_type);
$isMultiple = $hasType && strpos($this->_type, '[]') !== false;
if ($hasType) {
$value = $this->_castToExpression($value, $this->_type);
}
if ($isMultiple) {
$this->_valueExpressions = $this->_collectExpressions($value);
}
$this->_isMultiple = $isMultiple;
$this->_value = $value;
}
@@ -157,6 +169,13 @@ public function traverse(callable $callable)
$callable($this->_value);
$this->_value->traverse($callable);
}
if (!empty($this->_valueExpressions)) {
foreach ($this->_valueExpressions as $v) {
$callable($v);
$v->traverse($callable);
}
}
}
/**
@@ -190,7 +209,7 @@ protected function _stringExpression($generator)
$template = '(%s) ';
}
if (strpos($this->_type, '[]') !== false) {
if ($this->_isMultiple) {
$template .= '%s (%s)';
$type = str_replace('[]', '', $this->_type);
$value = $this->_flattenValue($this->_value, $generator, $type);
@@ -239,9 +258,25 @@ protected function _flattenValue($value, $generator, $type = null)
{
$parts = [];
foreach ($value as $k => $v) {
if (isset($this->_valueExpressions[$k])) {
$parts[] = $this->_valueExpressions[$k]->sql($generator);
continue;
}
$parts[] = $this->_bindValue($v, $generator, $type);
}
return implode(',', $parts);
}
protected function _collectExpressions($values)
{
$result = [];
foreach ($values as $k => $v) {
if ($v instanceof ExpressionInterface) {
$result[$k] = $v;
}
}
return $result;
}
}
@@ -28,7 +28,8 @@ interface ExpressionTypeInterface
* Returns an ExpressionInterface object for the given value that can
* be used in queries.
*
* @param mixed $value The value to be converted to an expression
* @return \Cake\Database\ExpressionInterface
*/
public function toExpression($value, Driver $driver);
public function toExpression($value);
}
@@ -26,15 +26,15 @@ trait TypeExpressionCasterTrait
protected function _castToExpression($value, $type)
{
return $value;
$baseType = str_replace('[]', '', $type);
$multi = $type !== $baseType;
$converter = Type::build($baseType);
if (!$converter instanceof ExpressionTypeInterface) {
return $value;
}
$multi = $type !== $baseType;
if ($multi) {
$result = [];
foreach ($value as $k => $v) {
@@ -0,0 +1,71 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The Open Group Test Suite License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since 3.3.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\Test\TestCase\Database;
use Cake\TestSuite\TestCase;
use Cake\Database\Type\StringType;
use Cake\Database\Type\ExpressionTypeInterface;
use Cake\Database\Expression\FunctionExpression;
use Cake\Database\ValueBinder;
use Cake\Database\Type;
use Cake\Database\Expression\Comparison;
class TestType extends StringType implements ExpressionTypeInterface
{
public function toExpression($value)
{
return new FunctionExpression('CONCAT', [$value, ' - foo']);
}
}
/**
* Tests for Expression objects casting values to other expressions
* using the type classes
*
*/
class FunctionsBuilderTest extends TestCase
{
/**
* Setups a mock for FunctionsBuilder
*
* @return void
*/
public function setUp()
{
parent::setUp();
Type::map('test', new TestType);
}
public function testComparisonSimple()
{
$comparison = new Comparison('field', 'the thing', 'test', '=');
$binder = new ValueBinder;
$sql = $comparison->sql($binder);
$this->assertEquals('field = (CONCAT(:c0, :c1))', $sql);
$this->assertEquals('the thing', $binder->bindings()[':c0']['value']);
}
public function testComparisonMultiple()
{
$comparison = new Comparison('field', ['2', '3'], 'test[]', 'IN');
$binder = new ValueBinder;
$sql = $comparison->sql($binder);
$this->assertEquals('field IN (CONCAT(:c0, :c1),CONCAT(:c2, :c3))', $sql);
$this->assertEquals('2', $binder->bindings()[':c0']['value']);
$this->assertEquals('3', $binder->bindings()[':c2']['value']);
}
}

0 comments on commit 98a5267

Please sign in to comment.
You can’t perform that action at this time.