diff --git a/Event/Listener/DoctrineApplyFilterListener.php b/Event/Listener/DoctrineApplyFilterListener.php index f7091c3..78efa12 100644 --- a/Event/Listener/DoctrineApplyFilterListener.php +++ b/Event/Listener/DoctrineApplyFilterListener.php @@ -2,12 +2,14 @@ namespace Lexik\Bundle\FormFilterBundle\Event\Listener; -use Doctrine\ORM\Query\Expr\Composite; +use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Query\Expression\CompositeExpression; +use Doctrine\ORM\Query\Expr\Composite; use Lexik\Bundle\FormFilterBundle\Event\ApplyFilterConditionEvent; use Lexik\Bundle\FormFilterBundle\Filter\Condition\ConditionInterface; use Lexik\Bundle\FormFilterBundle\Filter\Condition\ConditionNodeInterface; use Lexik\Bundle\FormFilterBundle\Filter\Doctrine\DoctrineQueryBuilderAdapter; +use Lexik\Bundle\FormFilterBundle\Filter\Doctrine\Expression\ExpressionParameterValue; /** * Add filter conditions on a Doctrine ORM or DBAL query builder. @@ -49,9 +51,12 @@ public function onApplyFilterCondition(ApplyFilterConditionEvent $event) $qbAdapter->{$this->whereMethod}($expression); foreach ($this->parameters as $name => $value) { - if (is_array($value)) { - list($value, $type) = $value; - $qbAdapter->setParameter($name, $value, $type); + if ($value instanceof ExpressionParameterValue) { + $qbAdapter->setParameter($name, $value->value, $value->type); + } elseif (is_array($value) && count($value) === 2 && Type::hasType($value[1])) { + // that could be deprecated in favor of the ExpressionParameterValue class above + // as it is kind of a hacky solution for a legacy architectural decision + $qbAdapter->setParameter($name, $value[0], $value[1]); } else { $qbAdapter->setParameter($name, $value); } diff --git a/Event/Subscriber/AbstractDoctrineSubscriber.php b/Event/Subscriber/AbstractDoctrineSubscriber.php index e2b2cba..bb006bc 100644 --- a/Event/Subscriber/AbstractDoctrineSubscriber.php +++ b/Event/Subscriber/AbstractDoctrineSubscriber.php @@ -2,6 +2,7 @@ namespace Lexik\Bundle\FormFilterBundle\Event\Subscriber; +use Lexik\Bundle\FormFilterBundle\Filter\Doctrine\Expression\ExpressionParameterValue; use Lexik\Bundle\FormFilterBundle\Filter\FilterOperands; use Lexik\Bundle\FormFilterBundle\Filter\Form\Type\BooleanFilterType; use Lexik\Bundle\FormFilterBundle\Event\GetFilterConditionEvent; @@ -30,12 +31,12 @@ public function filterValue(GetFilterConditionEvent $event) if (is_array($values['value']) && sizeof($values['value']) > 0) { $event->setCondition( $expr->in($event->getField(), ':'.$paramName), - array($paramName => array($values['value'], Connection::PARAM_STR_ARRAY)) + array($paramName => new ExpressionParameterValue($values['value'], Connection::PARAM_STR_ARRAY)) ); } elseif (!is_array($values['value'])) { $event->setCondition( $expr->eq($event->getField(), ':'.$paramName), - array($paramName => array($values['value'], Types::STRING)) + array($paramName => new ExpressionParameterValue($values['value'], Types::STRING)) ); } } @@ -56,7 +57,7 @@ public function filterBoolean(GetFilterConditionEvent $event) $event->setCondition( $expr->eq($event->getField(), ':'.$paramName), - array($paramName => array($value, Types::BOOLEAN)) + array($paramName => new ExpressionParameterValue($value, Types::BOOLEAN)) ); } } @@ -74,7 +75,7 @@ public function filterCheckbox(GetFilterConditionEvent $event) $event->setCondition( $expr->eq($event->getField(), ':'.$paramName), - array($paramName => array($values['value'], Types::STRING)) + array($paramName => new ExpressionParameterValue($values['value'], Types::STRING)) ); } } @@ -92,7 +93,7 @@ public function filterDate(GetFilterConditionEvent $event) $event->setCondition( $expr->eq($event->getField(), ':'.$paramName), - array($paramName => array($values['value'], Types::DATE_MUTABLE)) + array($paramName => new ExpressionParameterValue($values['value'], Types::DATE_MUTABLE)) ); } } @@ -124,7 +125,7 @@ public function filterDateTime(GetFilterConditionEvent $event) $event->setCondition( $expr->eq($event->getField(), ':'.$paramName), - array($paramName => array($values['value'], Types::DATETIME_MUTABLE)) + array($paramName => new ExpressionParameterValue($values['value'], Types::DATETIME_MUTABLE)) ); } } @@ -158,7 +159,7 @@ public function filterNumber(GetFilterConditionEvent $event) $event->setCondition( $expr->$op($event->getField(), ':'.$paramName), - array($paramName => array($values['value'], is_int($values['value']) ? Types::INTEGER : Types::FLOAT)) + array($paramName => new ExpressionParameterValue($values['value'], is_int($values['value']) ? Types::INTEGER : Types::FLOAT)) ); } } @@ -211,7 +212,7 @@ public function filterNumberRange(GetFilterConditionEvent $event) $rightParamName = sprintf('p_%s_right', str_replace('.', '_', $event->getField())); $expression->add($expr->$rightCond($event->getField(), ':'.$rightParamName)); - $params[$rightParamName] = array($rightValue, is_int($rightValue) ? Types::INTEGER : Types::FLOAT); + $params[$rightParamName] = new ExpressionParameterValue($rightValue, is_int($rightValue) ? Types::INTEGER : Types::FLOAT); } } diff --git a/Event/Subscriber/DoctrineORMSubscriber.php b/Event/Subscriber/DoctrineORMSubscriber.php index 3db9776..4a70dee 100644 --- a/Event/Subscriber/DoctrineORMSubscriber.php +++ b/Event/Subscriber/DoctrineORMSubscriber.php @@ -9,6 +9,7 @@ use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\Mapping\ClassMetadataInfo; use Lexik\Bundle\FormFilterBundle\Event\GetFilterConditionEvent; +use Lexik\Bundle\FormFilterBundle\Filter\Doctrine\Expression\ExpressionParameterValue; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** @@ -100,13 +101,13 @@ public function filterEntity(GetFilterConditionEvent $event) if (count($ids) > 0) { $event->setCondition( $expr->in($filterField, ':'.$paramName), - array($paramName => array($ids, Connection::PARAM_INT_ARRAY)) + array($paramName => new ExpressionParameterValue($ids, Connection::PARAM_INT_ARRAY)) ); } } else { $event->setCondition( $expr->eq($filterField, ':'.$paramName), - array($paramName => array( + array($paramName => new ExpressionParameterValue( $this->getEntityIdentifier($values['value'], $queryBuilder->getEntityManager()), Types::INTEGER )) diff --git a/Filter/Condition/Condition.php b/Filter/Condition/Condition.php index ff272d8..e7459a1 100644 --- a/Filter/Condition/Condition.php +++ b/Filter/Condition/Condition.php @@ -20,11 +20,12 @@ class Condition implements ConditionInterface private $expression; /** - * @var array + * @var array * * array( * 'param_name_1' => $value, - * 'param_nema_2 => array($value, $type), + * 'param_name_2 => ExpressionParameterValue($value, $type = null), + * 'param_name_3 => array($value, $type), // can be deprecated, as it interferes with array values (link for IN() expressions) * ) */ private $parameters; diff --git a/Filter/Doctrine/Expression/ExpressionParameterValue.php b/Filter/Doctrine/Expression/ExpressionParameterValue.php new file mode 100644 index 0000000..07ca13a --- /dev/null +++ b/Filter/Doctrine/Expression/ExpressionParameterValue.php @@ -0,0 +1,30 @@ +value = $value; + $this->type = $type; + } +} diff --git a/Tests/Filter/Doctrine/DBALQueryBuilderUpdaterTest.php b/Tests/Filter/Doctrine/DBALQueryBuilderUpdaterTest.php index 06d6279..78ae86f 100644 --- a/Tests/Filter/Doctrine/DBALQueryBuilderUpdaterTest.php +++ b/Tests/Filter/Doctrine/DBALQueryBuilderUpdaterTest.php @@ -32,7 +32,7 @@ public function testDisabledFieldQuery() public function testApplyFilterOption() { parent::createApplyFilterOptionTest('getSQL', array( - 'SELECT i FROM item i WHERE (i.name <> \'blabla\') AND (i.position <> 2)', + 'SELECT i FROM item i WHERE (i.name <> :name) AND (i.position <> :position)', )); } @@ -82,7 +82,7 @@ public function testDateTimeRange() public function testFilterStandardType() { parent::createFilterStandardTypeTest('getSQL', array( - 'SELECT i FROM item i WHERE (i.name LIKE \'%hey dude%\') AND (i.position = 99)', + 'SELECT i FROM item i WHERE (i.name LIKE \'%hey dude%\') AND (i.position = :position)', )); } diff --git a/Tests/Filter/Doctrine/ORMQueryBuilderUpdaterTest.php b/Tests/Filter/Doctrine/ORMQueryBuilderUpdaterTest.php index e40ca1c..02e9d24 100644 --- a/Tests/Filter/Doctrine/ORMQueryBuilderUpdaterTest.php +++ b/Tests/Filter/Doctrine/ORMQueryBuilderUpdaterTest.php @@ -35,7 +35,7 @@ public function testDisabledFieldQuery() public function testApplyFilterOption() { parent::createApplyFilterOptionTest('getDQL', array( - 'SELECT i FROM Lexik\Bundle\FormFilterBundle\Tests\Fixtures\Entity\Item i WHERE i.name <> \'blabla\' AND i.position <> 2', + 'SELECT i FROM Lexik\Bundle\FormFilterBundle\Tests\Fixtures\Entity\Item i WHERE i.name <> :name AND i.position <> :position', )); } @@ -85,7 +85,7 @@ public function testDateTimeRange() public function testFilterStandardType() { parent::createFilterStandardTypeTest('getDQL', array( - 'SELECT i FROM Lexik\Bundle\FormFilterBundle\Tests\Fixtures\Entity\Item i WHERE i.name LIKE \'%hey dude%\' AND i.position = 99', + 'SELECT i FROM Lexik\Bundle\FormFilterBundle\Tests\Fixtures\Entity\Item i WHERE i.name LIKE \'%hey dude%\' AND i.position = :position', )); } diff --git a/Tests/Fixtures/Filter/FormType.php b/Tests/Fixtures/Filter/FormType.php index 97b79e0..8b51793 100644 --- a/Tests/Fixtures/Filter/FormType.php +++ b/Tests/Fixtures/Filter/FormType.php @@ -3,6 +3,7 @@ namespace Lexik\Bundle\FormFilterBundle\Tests\Fixtures\Filter; use Doctrine\ODM\MongoDB\Query\Expr; +use Lexik\Bundle\FormFilterBundle\Filter\Doctrine\Expression\ExpressionParameterValue; use Lexik\Bundle\FormFilterBundle\Filter\Query\QueryInterface; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; @@ -24,11 +25,12 @@ public function buildForm(FormBuilderInterface $builder, array $options) if (!empty($values['value'])) { if ($filterQuery->getExpr() instanceof Expr) { $expr = $filterQuery->getExpr()->field($field)->equals($values['value']); - } else { - $expr = $filterQuery->getExpr()->eq($field, $values['value']); + return $filterQuery->createCondition($expr); } - - return $filterQuery->createCondition($expr); + return $filterQuery->createCondition( + $filterQuery->getExpr()->eq($field, ':position'), + ['position' => new ExpressionParameterValue($values['value'])] + ); } return null; diff --git a/Tests/Fixtures/Filter/ItemCallbackFilterType.php b/Tests/Fixtures/Filter/ItemCallbackFilterType.php index b2d29f7..f9056c8 100644 --- a/Tests/Fixtures/Filter/ItemCallbackFilterType.php +++ b/Tests/Fixtures/Filter/ItemCallbackFilterType.php @@ -3,6 +3,7 @@ namespace Lexik\Bundle\FormFilterBundle\Tests\Fixtures\Filter; use Doctrine\ODM\MongoDB\Query\Expr; +use Lexik\Bundle\FormFilterBundle\Filter\Doctrine\Expression\ExpressionParameterValue; use Lexik\Bundle\FormFilterBundle\Filter\Form\Type\NumberFilterType; use Lexik\Bundle\FormFilterBundle\Filter\Form\Type\TextFilterType; use Lexik\Bundle\FormFilterBundle\Filter\Query\QueryInterface; @@ -26,11 +27,12 @@ public function buildForm(FormBuilderInterface $builder, array $options) if (!empty($values['value'])) { if ($filterQuery->getExpr() instanceof Expr) { $expr = $filterQuery->getExpr()->field($field)->notEqual($values['value']); - } else { - $expr = $filterQuery->getExpr()->neq($field, $values['value']); + return $filterQuery->createCondition($expr); } - - return $filterQuery->createCondition($expr); + return $filterQuery->createCondition( + $filterQuery->getExpr()->neq($field, ':position'), + ['position' => new ExpressionParameterValue($values['value'])] + ); } return null; @@ -51,11 +53,13 @@ public function fieldNameCallback(QueryInterface $filterQuery, $field, $values) if (!empty($values['value'])) { if ($filterQuery->getExpr() instanceof Expr) { $expr = $filterQuery->getExpr()->field($field)->notEqual($values['value']); - } else { - $expr = $filterQuery->getExpr()->neq($field, sprintf('\'%s\'', $values['value'])); + return $filterQuery->createCondition($expr); } - - return $filterQuery->createCondition($expr); + $paramName = substr($field, strrpos($field, '.') + (false === strrpos($field, '.') ? 0 : 1)); + return $filterQuery->createCondition( + $filterQuery->getExpr()->neq($field, ':' . $paramName), + [$paramName => new ExpressionParameterValue($values['value'])] + ); } return null;