diff --git a/composer.json b/composer.json index a03178c8..299804c3 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,6 @@ }, "require-dev": { "phpspec/phpspec": "~2.1@dev", - "henrikbjorn/phpspec-code-coverage": "0.2.*", "satooshi/php-coveralls": "0.6.*" }, "autoload": { diff --git a/spec/Happyr/DoctrineSpecification/DoctrineTransformerSpec.php b/spec/Happyr/DoctrineSpecification/DoctrineTransformerSpec.php new file mode 100644 index 00000000..cb967acf --- /dev/null +++ b/spec/Happyr/DoctrineSpecification/DoctrineTransformerSpec.php @@ -0,0 +1,179 @@ +expr()->willReturn($expr); + $this->beConstructedWith($queryBuilder); + } + + function it_is_initializable() + { + $this->shouldHaveType('Happyr\DoctrineSpecification\DoctrineTransformer'); + } + + function it_should_transform_is_not_null(Expr $expr, ParametersBag $parameters) + { + $expr->isNotNull('field')->willReturn('field IS NOT NULL'); + $this->getDqlPart(new IsNotNull('field'), $parameters)->shouldReturn('field IS NOT NULL'); + } + + function it_should_transform_is_null(Expr $expr, ParametersBag $parameters) + { + $expr->isNull('field')->willReturn('field IS NULL'); + + $this->getDqlPart(new IsNull('field'), $parameters)->shouldReturn('field IS NULL'); + } + + function it_should_transform_equals(Expr $expr, ParametersBag $parameters) + { + $parameters->getLastName()->willReturn('?1'); + $parameters->add(Argument::any())->shouldBeCalled(); + $expr->eq('field', '?1')->willReturn('field = ?1'); + + $this->getDqlPart(new Equals('field', 'value'), $parameters)->shouldReturn('field = ?1'); + } + + function it_should_transform_greater_than_or_equals(Expr $expr, ParametersBag $parameters) + { + $parameters->add(Argument::any())->shouldBeCalled(); + $parameters->getLastName()->willReturn('?1'); + $expr->gte('field', '?1')->willReturn('field >= ?1'); + + $this->getDqlPart(new GreaterOrEqualThan('field', 'value'), $parameters)->shouldReturn('field >= ?1'); + } + + function it_should_transform_greater_than(Expr $expr, ParametersBag $parameters) + { + $parameters->add(Argument::any())->shouldBeCalled(); + $parameters->getLastName()->willReturn('?1'); + $expr->gt('field', '?1')->willReturn('field > ?1'); + + $this->getDqlPart(new GreaterThan('field', 'value'), $parameters)->shouldReturn('field > ?1'); + } + + function it_should_transform_in(Expr $expr, ParametersBag $parameters) + { + $parameters->add(Argument::any())->shouldBeCalled(); + $parameters->getLastName()->willReturn('?1'); + $expr->in('field', '?1')->willReturn('field IN (\'?1\')'); + + $this->getDqlPart(new In('field', [1,2,3]), $parameters)->shouldReturn('field IN (\'?1\')'); + } + + function it_should_transform_less_or_equals(Expr $expr, ParametersBag $parameters) + { + $parameters->add(Argument::any())->shouldBeCalled(); + $parameters->getLastName()->willReturn('?1'); + $expr->lte('field', '?1')->willReturn('field <= ?1'); + + $this->getDqlPart(new LessOrEqualThan('field', 'value'), $parameters)->shouldReturn('field <= ?1'); + } + + function it_should_transform_less_than_or_equals(Expr $expr, ParametersBag $parameters) + { + $parameters->add(Argument::any())->shouldBeCalled(); + $parameters->getLastName()->willReturn('?1'); + $expr->lt('field', '?1')->willReturn('field < ?1'); + + $this->getDqlPart(new LessThan('field', 'value'), $parameters)->shouldReturn('field < ?1'); + } + + function it_should_transform_like_contains(Expr $expr, ParametersBag $parameters) + { + $parameters->add(Argument::any())->shouldBeCalled(); + $parameters->getLastName()->willReturn('?1'); + $expr->like('field', '?1')->willReturn('field like ?1'); + + $this->getDqlPart(new Like('field', 'value', Like::CONTAINS), $parameters)->shouldReturn('field like ?1'); + } + + function it_should_transform_like_starts_with(Expr $expr, ParametersBag $parameters) + { + $parameters->add(Argument::any())->shouldBeCalled(); + $parameters->getLastName()->willReturn('?1'); + $expr->like('field', '?1')->willReturn('field like ?1'); + + $this->getDqlPart(new Like('field', 'value', Like::STARTS_WITH), $parameters)->shouldReturn('field like ?1'); + } + + function it_should_transform_ends_with(Expr $expr, ParametersBag $parameters) + { + $parameters->add(Argument::any())->shouldBeCalled(); + $parameters->getLastName()->willReturn('?1'); + $expr->like('field', '?1')->willReturn('field like ?1'); + + $this->getDqlPart(new Like('field', 'value', Like::ENDS_WITH), $parameters)->shouldReturn('field like ?1'); + } + + function it_should_transform_not_equals(Expr $expr, ParametersBag $parameters) + { + $parameters->add(Argument::any())->shouldBeCalled(); + $parameters->getLastName()->willReturn('?1'); + $expr->neq('field', '?1')->willReturn('field <> ?1'); + + $this->getDqlPart(new NotEquals('field', 'value'), $parameters)->shouldReturn('field <> ?1'); + } + + function it_should_transform_not(Expr $expr, ParametersBag $parameters) + { + $parameters->getLastName()->willReturn('?1'); + $parameters->add(Argument::any())->shouldBeCalled(); + $expr->eq('field', '?1')->willReturn('field = ?1'); + $expr->not('field = ?1')->willReturn('NOT (field = ?1)'); + + $this->getDqlPart(new Not(new Equals('field', 'value')), $parameters)->shouldReturn('NOT (field = ?1)'); + } + + function it_should_transform_and(Expr $expr) + { + $parameters = new ParametersBag(); + + $expr->eq('field', '?1')->willReturn('field = ?1'); + $expr->eq('field', '?2')->willReturn('field = ?2'); + $expr->andX('field = ?1', 'field = ?2')->willReturn('field = ?1 AND field = ?2'); + + $this->getDqlPart(new AndX(new Equals('field', 'value1'), new Equals('field', 'value2')), $parameters)->shouldReturn('field = ?1 AND field = ?2'); + } + + function it_should_transform_or(Expr $expr) + { + $parameters = new ParametersBag(); + + $expr->eq('field', '?1')->willReturn('field = ?1'); + $expr->eq('field', '?2')->willReturn('field = ?2'); + $expr->orX('field = ?1', 'field = ?2')->willReturn('field = ?1 OR field = ?2'); + + $this->getDqlPart(new OrX(new Equals('field', 'value1'), new Equals('field', 'value2')), $parameters)->shouldReturn('field = ?1 OR field = ?2'); + } + + +} diff --git a/spec/Happyr/DoctrineSpecification/EntitySpecificationRepositorySpec.php b/spec/Happyr/DoctrineSpecification/EntitySpecificationRepositorySpec.php deleted file mode 100644 index 79573fff..00000000 --- a/spec/Happyr/DoctrineSpecification/EntitySpecificationRepositorySpec.php +++ /dev/null @@ -1,70 +0,0 @@ -beConstructedWith($entityManager, $classMetadata); - } - - function it_matches_a_specification_without_result_modifier( - Specification $specification, - EntityManager $entityManager, - QueryBuilder $qb, - AbstractQuery $query - ) - { - $this->prepareStubs($specification, $entityManager, $qb, $query); - - $specification->modify($qb, $this->alias)->shouldBeCalled(); - - $this->match($specification)->shouldReturn($this->result); - } - - function it_matches_a_specification_with_result_modifier( - Specification $specification, - EntityManager $entityManager, - QueryBuilder $qb, - AbstractQuery $query, - ResultModifier $modifier - ) - { - $this->prepareStubs($specification, $entityManager, $qb, $query); - - $specification->modify($qb, $this->alias)->shouldBeCalled(); - $modifier->modify($query)->shouldBeCalled(); - - $this->match($specification, $modifier)->shouldReturn($this->result); - } - - private function prepareStubs(Specification $specification, EntityManager $entityManager, QueryBuilder $qb, AbstractQuery $query) - { - $entityManager->createQueryBuilder()->willReturn($qb); - $specification->getFilter($qb, $this->alias)->willReturn($this->expression); - $qb->from(Argument::any(), $this->alias)->willReturn($qb); - $qb->select($this->alias)->willReturn($qb); - $qb->where($this->expression)->willReturn($qb); - $qb->getQuery()->willReturn($query); - $query->execute()->willReturn($this->result); - } -} diff --git a/spec/Happyr/DoctrineSpecification/Filter/ComparisonSpec.php b/spec/Happyr/DoctrineSpecification/Filter/ComparisonSpec.php deleted file mode 100644 index fd045293..00000000 --- a/spec/Happyr/DoctrineSpecification/Filter/ComparisonSpec.php +++ /dev/null @@ -1,54 +0,0 @@ -beConstructedWith(Comparison::GT, 'age', 18, 'a'); - } - - function it_is_an_expression() - { - $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Filter\Filter'); - } - - function it_returns_comparison_object(QueryBuilder $qb, ArrayCollection $parameters) - { - $qb->getParameters()->willReturn($parameters); - $parameters->count()->willReturn(10); - - $qb->setParameter('comparison_10', 18)->shouldBeCalled(); - - $comparison = $this->getFilter($qb, null); - - $comparison->shouldReturn('a.age > :comparison_10'); - } - - function it_uses_comparison_specific_dql_alias_if_passed(QueryBuilder $qb, ArrayCollection $parameters) - { - $this->beConstructedWith(Comparison::GT, 'age', 18, null); - - $qb->getParameters()->willReturn($parameters); - $parameters->count()->willReturn(10); - - $qb->setParameter('comparison_10', 18)->shouldBeCalled(); - - $this->getFilter($qb, 'x')->shouldReturn('x.age > :comparison_10'); - } - - function it_validates_operator() - { - $this->shouldThrow('Happyr\DoctrineSpecification\Exception\InvalidArgumentException')->during('__construct', array('==', 'age', 18, null)); - } -} diff --git a/spec/Happyr/DoctrineSpecification/Filter/EqualsSpec.php b/spec/Happyr/DoctrineSpecification/Filter/EqualsSpec.php new file mode 100644 index 00000000..982472ad --- /dev/null +++ b/spec/Happyr/DoctrineSpecification/Filter/EqualsSpec.php @@ -0,0 +1,32 @@ +beConstructedWith('field', 'value'); + } + + function it_is_a_filter() + { + $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Filter\Base\FilterInterface'); + } + + function it_has_field_name() + { + $this->getField()->shouldReturn('field'); + } + + function it_has_field_value() + { + $this->getValue()->shouldReturn('value'); + } +} diff --git a/spec/Happyr/DoctrineSpecification/Filter/GreaterOrEqualThanSpec.php b/spec/Happyr/DoctrineSpecification/Filter/GreaterOrEqualThanSpec.php new file mode 100644 index 00000000..f1603e2f --- /dev/null +++ b/spec/Happyr/DoctrineSpecification/Filter/GreaterOrEqualThanSpec.php @@ -0,0 +1,30 @@ +beConstructedWith('field', 'value'); + } + + function it_is_a_filter() + { + $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Filter\Base\FilterInterface'); + } + + function it_has_field_name() + { + $this->getField()->shouldReturn('field'); + } + + function it_has_field_value() + { + $this->getValue()->shouldReturn('value'); + } +} diff --git a/spec/Happyr/DoctrineSpecification/Filter/GreaterThanSpec.php b/spec/Happyr/DoctrineSpecification/Filter/GreaterThanSpec.php new file mode 100644 index 00000000..3aab5cf1 --- /dev/null +++ b/spec/Happyr/DoctrineSpecification/Filter/GreaterThanSpec.php @@ -0,0 +1,30 @@ +beConstructedWith('field', 'value'); + } + + function it_is_a_filter() + { + $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Filter\Base\FilterInterface'); + } + + function it_has_field_name() + { + $this->getField()->shouldReturn('field'); + } + + function it_has_field_value() + { + $this->getValue()->shouldReturn('value'); + } +} diff --git a/spec/Happyr/DoctrineSpecification/Filter/InSpec.php b/spec/Happyr/DoctrineSpecification/Filter/InSpec.php index bf526425..0867af04 100644 --- a/spec/Happyr/DoctrineSpecification/Filter/InSpec.php +++ b/spec/Happyr/DoctrineSpecification/Filter/InSpec.php @@ -2,43 +2,31 @@ namespace spec\Happyr\DoctrineSpecification\Filter; -use Doctrine\Common\Collections\ArrayCollection; -use Doctrine\ORM\Query\Expr; -use Doctrine\ORM\QueryBuilder; use Happyr\DoctrineSpecification\Filter\In; use PhpSpec\ObjectBehavior; -use Prophecy\Argument; /** * @mixin In */ class InSpec extends ObjectBehavior { - private $field='foobar'; - - private $value=array('bar', 'baz'); - function let() { - $this->beConstructedWith($this->field, $this->value, 'a'); + $this->beConstructedWith('field', 'value'); } - function it_is_an_expression() + function it_is_a_filter() { - $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Filter\Filter'); + $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Filter\Base\FilterInterface'); } - function it_returns_expression_func_object(QueryBuilder $qb, ArrayCollection $parameters, Expr $expr) + function it_has_field_name() { - $dqlAlias = 'a'; - $qb->expr()->willReturn($expr); - $expr->in(sprintf('%s.%s', $dqlAlias, $this->field), ':in_10')->shouldBeCalled(); - - $qb->getParameters()->willReturn($parameters); - $parameters->count()->willReturn(10); - - $qb->setParameter('in_10', $this->value)->shouldBeCalled(); + $this->getField()->shouldReturn('field'); + } - $this->getFilter($qb, null); + function it_has_field_value() + { + $this->getValue()->shouldReturn('value'); } } diff --git a/spec/Happyr/DoctrineSpecification/Filter/IsNotNullSpec.php b/spec/Happyr/DoctrineSpecification/Filter/IsNotNullSpec.php index ef208622..f667d8c5 100644 --- a/spec/Happyr/DoctrineSpecification/Filter/IsNotNullSpec.php +++ b/spec/Happyr/DoctrineSpecification/Filter/IsNotNullSpec.php @@ -2,51 +2,26 @@ namespace spec\Happyr\DoctrineSpecification\Filter; -use Doctrine\ORM\Query\Expr; -use Doctrine\ORM\QueryBuilder; use Happyr\DoctrineSpecification\Filter\IsNotNull; use PhpSpec\ObjectBehavior; -use Prophecy\Argument; /** * @mixin IsNotNull */ class IsNotNullSpec extends ObjectBehavior { - private $field='foobar'; - - private $dqlAlias = 'a'; - function let() { - $this->beConstructedWith($this->field, $this->dqlAlias); - } - - function it_is_an_expression() - { - $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Filter\Filter'); + $this->beConstructedWith('field'); } - /** - * returns expression func object - */ - function it_calls_not_null(QueryBuilder $qb, Expr $expr) + function it_is_a_filter() { - $expression = 'a.foobar is not null'; - - $qb->expr()->willReturn($expr); - $expr->isNotNull(sprintf('%s.%s', $this->dqlAlias, $this->field))->willReturn($expression); - - $this->getFilter($qb, null)->shouldReturn($expression); + $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Filter\Base\FilterInterface'); } - function it_uses_dql_alias_if_passed(QueryBuilder $qb, Expr $expr) + function it_has_field_name() { - $dqlAlias='x'; - $this->beConstructedWith($this->field, null); - $qb->expr()->willReturn($expr); - - $expr->isNotNull(sprintf('%s.%s', $dqlAlias, $this->field))->shouldBeCalled(); - $this->getFilter($qb, $dqlAlias); + $this->getField()->shouldReturn('field'); } } diff --git a/spec/Happyr/DoctrineSpecification/Filter/IsNullSpec.php b/spec/Happyr/DoctrineSpecification/Filter/IsNullSpec.php index 74de981a..be0c22ca 100644 --- a/spec/Happyr/DoctrineSpecification/Filter/IsNullSpec.php +++ b/spec/Happyr/DoctrineSpecification/Filter/IsNullSpec.php @@ -2,51 +2,26 @@ namespace spec\Happyr\DoctrineSpecification\Filter; -use Doctrine\ORM\Query\Expr; -use Doctrine\ORM\QueryBuilder; use Happyr\DoctrineSpecification\Filter\IsNull; use PhpSpec\ObjectBehavior; -use Prophecy\Argument; /** * @mixin IsNull */ class IsNullSpec extends ObjectBehavior { - private $field='foobar'; - - private $dqlAlias = 'a'; - function let() { - $this->beConstructedWith($this->field, $this->dqlAlias); - } - - function it_is_an_expression() - { - $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Filter\Filter'); + $this->beConstructedWith('field'); } - /** - * returns expression func object - */ - function it_calls_null(QueryBuilder $qb, Expr $expr) + function it_is_a_filter() { - $expression = 'a.foobar is null'; - - $qb->expr()->willReturn($expr); - $expr->isNull(sprintf('%s.%s', $this->dqlAlias, $this->field))->willReturn($expression); - - $this->getFilter($qb, 'b')->shouldReturn($expression); + $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Filter\Base\FilterInterface'); } - function it_uses_dql_alias_if_passed(QueryBuilder $qb, Expr $expr) + function it_has_field_name() { - $dqlAlias = 'x'; - $this->beConstructedWith($this->field, null); - $qb->expr()->willReturn($expr); - - $expr->isNull(sprintf('%s.%s', $dqlAlias, $this->field))->shouldBeCalled(); - $this->getFilter($qb, $dqlAlias); + $this->getField()->shouldReturn('field'); } } diff --git a/spec/Happyr/DoctrineSpecification/Filter/LessOrEqualThanSpec.php b/spec/Happyr/DoctrineSpecification/Filter/LessOrEqualThanSpec.php new file mode 100644 index 00000000..74dd0ff4 --- /dev/null +++ b/spec/Happyr/DoctrineSpecification/Filter/LessOrEqualThanSpec.php @@ -0,0 +1,30 @@ +beConstructedWith('field', 'value'); + } + + function it_is_a_filter() + { + $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Filter\Base\FilterInterface'); + } + + function it_has_field_name() + { + $this->getField()->shouldReturn('field'); + } + + function it_has_field_value() + { + $this->getValue()->shouldReturn('value'); + } +} diff --git a/spec/Happyr/DoctrineSpecification/Filter/LessThanSpec.php b/spec/Happyr/DoctrineSpecification/Filter/LessThanSpec.php new file mode 100644 index 00000000..b034a40f --- /dev/null +++ b/spec/Happyr/DoctrineSpecification/Filter/LessThanSpec.php @@ -0,0 +1,30 @@ +beConstructedWith('field', 'value'); + } + + function it_is_a_filter() + { + $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Filter\Base\FilterInterface'); + } + + function it_has_field_name() + { + $this->getField()->shouldReturn('field'); + } + + function it_has_field_value() + { + $this->getValue()->shouldReturn('value'); + } +} diff --git a/spec/Happyr/DoctrineSpecification/Filter/LikeSpec.php b/spec/Happyr/DoctrineSpecification/Filter/LikeSpec.php index 1b237c21..eb7be5a1 100644 --- a/spec/Happyr/DoctrineSpecification/Filter/LikeSpec.php +++ b/spec/Happyr/DoctrineSpecification/Filter/LikeSpec.php @@ -11,50 +11,28 @@ class LikeSpec extends ObjectBehavior { - private $field = "foo"; - - private $value = "bar"; - - public function let() + function let() { - $this->beConstructedWith($this->field, $this->value, Like::CONTAINS, "dqlAlias"); + $this->beConstructedWith('field', 'value', Like::CONTAINS); } - public function it_is_a_specification() + function it_is_a_filter() { - $this->shouldHaveType('Happyr\DoctrineSpecification\Specification'); + $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Filter\Base\FilterInterface'); } - public function it_surrounds_with_wildcards_when_using_contains(QueryBuilder $qb, ArrayCollection $parameters) + function it_has_field_name() { - $this->beConstructedWith($this->field, $this->value, Like::CONTAINS, "dqlAlias"); - $qb->getParameters()->willReturn($parameters); - $parameters->count()->willReturn(1); - - $qb->setParameter("comparison_1", "%bar%")->shouldBeCalled(); - - $this->match($qb, null); + $this->getField()->shouldReturn('field'); } - public function it_starts_with_wildcard_when_using_ends_with(QueryBuilder $qb, ArrayCollection $parameters) + function it_has_field_value() { - $this->beConstructedWith($this->field, $this->value, Like::ENDS_WITH, "dqlAlias"); - $qb->getParameters()->willReturn($parameters); - $parameters->count()->willReturn(1); - - $qb->setParameter("comparison_1", "%bar")->shouldBeCalled(); - - $this->match($qb, null); + $this->getValue()->shouldReturn('value'); } - public function it_ends_with_wildcard_when_using_starts_with(QueryBuilder $qb, ArrayCollection $parameters) + function it_has_format() { - $this->beConstructedWith($this->field, $this->value, Like::STARTS_WITH, "dqlAlias"); - $qb->getParameters()->willReturn($parameters); - $parameters->count()->willReturn(1); - - $qb->setParameter("comparison_1", "bar%")->shouldBeCalled(); - - $this->match($qb, null); + $this->getFormat()->shouldReturn(Like::CONTAINS); } -} +} diff --git a/spec/Happyr/DoctrineSpecification/Filter/NotEqualsSpec.php b/spec/Happyr/DoctrineSpecification/Filter/NotEqualsSpec.php new file mode 100644 index 00000000..3dbb7838 --- /dev/null +++ b/spec/Happyr/DoctrineSpecification/Filter/NotEqualsSpec.php @@ -0,0 +1,30 @@ +beConstructedWith('field', 'value'); + } + + function it_is_a_filter() + { + $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Filter\Base\FilterInterface'); + } + + function it_has_field_name() + { + $this->getField()->shouldReturn('field'); + } + + function it_has_field_value() + { + $this->getValue()->shouldReturn('value'); + } +} diff --git a/spec/Happyr/DoctrineSpecification/Logic/LogicXSpec.php b/spec/Happyr/DoctrineSpecification/Logic/LogicXSpec.php deleted file mode 100644 index f506b56d..00000000 --- a/spec/Happyr/DoctrineSpecification/Logic/LogicXSpec.php +++ /dev/null @@ -1,67 +0,0 @@ -beConstructedWith(self::EXPRESSION, array($specificationA, $specificationB)); - } - - function it_is_a_specification() - { - $this->shouldHaveType('Happyr\DoctrineSpecification\Specification'); - } - - function it_modifies_all_child_queries(QueryBuilder $queryBuilder, Specification $specificationA, Specification $specificationB) - { - $dqlAlias = 'a'; - - $specificationA->modify($queryBuilder, $dqlAlias)->shouldBeCalled(); - $specificationB->modify($queryBuilder, $dqlAlias)->shouldBeCalled(); - - $this->modify($queryBuilder, $dqlAlias); - } - - function it_composes_and_child_with_expression(QueryBuilder $qb, Expr $expression, Specification $specificationA, Specification $specificationB, $x, $y) - { - $dqlAlias = 'a'; - - $specificationA->getFilter($qb, $dqlAlias)->willReturn($x); - $specificationB->getFilter($qb, $dqlAlias)->willReturn($y); - $qb->expr()->willReturn($expression); - - $expression->{self::EXPRESSION}($x, $y)->shouldBeCalled(); - - $this->getFilter($qb, $dqlAlias); - } - - function it_supports_expressions(QueryBuilder $qb, Expr $expression, Filter $exprA, Filter $exprB, $x, $y) - { - $this->beConstructedWith(self::EXPRESSION, array($exprA, $exprB)); - - $dqlAlias = 'a'; - - $exprA->getFilter($qb, $dqlAlias)->willReturn($x); - $exprB->getFilter($qb, $dqlAlias)->willReturn($y); - $qb->expr()->willReturn($expression); - - $expression->{self::EXPRESSION}($x, $y)->shouldBeCalled(); - - $this->getFilter($qb, $dqlAlias); - } -} diff --git a/spec/Happyr/DoctrineSpecification/Logic/NotSpec.php b/spec/Happyr/DoctrineSpecification/Logic/NotSpec.php index 6c21f38f..72665b25 100644 --- a/spec/Happyr/DoctrineSpecification/Logic/NotSpec.php +++ b/spec/Happyr/DoctrineSpecification/Logic/NotSpec.php @@ -3,11 +3,8 @@ namespace spec\Happyr\DoctrineSpecification\Logic; use Doctrine\ORM\Query\Expr; -use Doctrine\ORM\QueryBuilder; use Happyr\DoctrineSpecification\Filter\Filter; use Happyr\DoctrineSpecification\Logic\Not; -use Happyr\DoctrineSpecification\Spec; -use Happyr\DoctrineSpecification\Specification; use PhpSpec\ObjectBehavior; use Prophecy\Argument; @@ -21,36 +18,8 @@ function let(Filter $filterExpr) $this->beConstructedWith($filterExpr, null); } - /** - * calls parent - */ - function it_calls_parent_match(QueryBuilder $qb, Expr $expr, Filter $filterExpr) - { - $dqlAlias = 'a'; - $expression = 'expression'; - $parentExpression = 'foobar'; - - $qb->expr()->willReturn($expr); - $filterExpr->getFilter($qb, $dqlAlias)->willReturn($parentExpression); - - $expr->not($parentExpression)->willReturn($expression); - - $this->getFilter($qb, $dqlAlias)->shouldReturn($expression); - } - - /** - * modifies parent query - */ - function it_modifies_parent_query(QueryBuilder $qb, Specification $spec) - { - $this->beConstructedWith($spec, null); - - $spec->modify($qb, 'a')->shouldBeCalled(); - $this->modify($qb, 'a'); - } - - function it_does_not_modify_parent_query(QueryBuilder $qb) - { - $this->modify($qb, 'a'); - } +// function it_is_a_specification() +// { +// $this->shouldHaveType('Happyr\DoctrineSpecification\Specification'); +// } } diff --git a/spec/Happyr/DoctrineSpecification/ParametersBagSpec.php b/spec/Happyr/DoctrineSpecification/ParametersBagSpec.php new file mode 100644 index 00000000..4e83b85d --- /dev/null +++ b/spec/Happyr/DoctrineSpecification/ParametersBagSpec.php @@ -0,0 +1,43 @@ +add('value'); + $this->getLastName()->shouldReturn('?1'); + $this->add('value2'); + $this->getLastName()->shouldReturn('?2'); + } + + function it_can_hold_parameters() + { + $this->hasAny()->shouldReturn(false); + $this->add('value'); + $this->hasAny()->shouldReturn(true); + } + + function it_should_be_able_to_reset_itself() + { + $this->add('value'); + $this->clearAll(); + $this->hasAny()->shouldReturn(false); + } + + function it_should_return_values() + { + $this->add('value'); + $this->getAll()->shouldReturn([1 => 'value']); + } +} diff --git a/spec/Happyr/DoctrineSpecification/SpecSpec.php b/spec/Happyr/DoctrineSpecification/SpecSpec.php deleted file mode 100644 index aed42ef3..00000000 --- a/spec/Happyr/DoctrineSpecification/SpecSpec.php +++ /dev/null @@ -1,18 +0,0 @@ -andX()->shouldReturnAnInstanceOf('Happyr\DoctrineSpecification\Logic\LogicX'); - } -} diff --git a/src/BaseSpecification.php b/src/BaseSpecification.php deleted file mode 100644 index fdd54cf2..00000000 --- a/src/BaseSpecification.php +++ /dev/null @@ -1,122 +0,0 @@ -dqlAlias = $dqlAlias; - } - - /** - * This method should return a Filter. You should overwrite this if you're not using BaseSpecification::$spec - * - * @return Filter - */ - protected function getFilterInstance() - { - return $this->spec; - } - - /** - * This method should return a QueryModifier. You should overwrite this if you're not using BaseSpecification::$spec - * - * @return QueryModifier - */ - protected function getQueryModifierInstance() - { - return $this->spec; - } - - /** - * @param QueryBuilder $qb - * @param string $dqlAlias - * - * @return string - */ - public function getFilter(QueryBuilder $qb, $dqlAlias) - { - $this->validate('getFilterInstance', 'Happyr\DoctrineSpecification\Filter\Filter'); - - if (null === $filter = $this->getFilterInstance()) { - return; - } - - return $filter->getFilter($qb, $this->getAlias($dqlAlias)); - } - - /** - * @param QueryBuilder $qb - * @param string $dqlAlias - */ - public function modify(QueryBuilder $qb, $dqlAlias) - { - $this->validate('getQueryModifierInstance', 'Happyr\DoctrineSpecification\Query\QueryModifier'); - - if (null === $queryModifier = $this->getQueryModifierInstance()) { - return; - } - - $queryModifier->modify($qb, $this->getAlias($dqlAlias)); - } - - /** - * @param string $getter - * @param string $class - * - * @throws LogicException - */ - private function validate($getter, $class) - { - $object = $this->$getter(); - // if $object is an object but not instance of $class - if (!is_null($object) && !is_a($object, $class)) { - throw new LogicException(sprintf( - 'Returned object must be an instance of %s. Please validate the %s::%s function and make it return instance of %s.', - $class, - get_class($this), - $getter, - $class - )); - } - } - - /** - * @param string $dqlAlias - * - * @return string - */ - private function getAlias($dqlAlias) - { - if ($this->dqlAlias !== null) { - return $this->dqlAlias; - } - - return $dqlAlias; - } -} \ No newline at end of file diff --git a/src/DoctrineTransformer.php b/src/DoctrineTransformer.php new file mode 100644 index 00000000..b2eb4170 --- /dev/null +++ b/src/DoctrineTransformer.php @@ -0,0 +1,211 @@ +queryBuilder = $queryBuilder; + $this->expression = $this->queryBuilder->expr(); + } + + /** + * Modify query builder according to specification + * + * @param FilterInterface $specification + * @return QueryBuilder modified query builder + */ + public function getQueryBuilder(FilterInterface $specification) + { + $parameters = new ParametersBag(); + $queryBuilder = clone $this->queryBuilder; + + $result = $this->getDQLPart($specification->getFilter(), $parameters); + $queryBuilder->add('where', $result); + + return $queryBuilder; + } + + /** + * Transform specification to DQL part + * + * @param FilterInterface $specification + * @param ParametersBag $parameters + * @return QueryBuilder modified query builder + */ + public function getDQLPart(FilterInterface $specification, ParametersBag $parameters) + { + return $this->getFilterDqlPart($specification, $parameters); + } + + private function getFilterDqlPart(FilterInterface $specification, ParametersBag $parameters) + { + switch (get_class($specification)) { + case 'Happyr\DoctrineSpecification\Filter\Equals': + + return $this->getDqlFromEquals($specification, $parameters); + case 'Happyr\DoctrineSpecification\Filter\GreaterOrEqualThan': + + return $this->getDqlFromGreaterOrEqualThan($specification, $parameters); + case 'Happyr\DoctrineSpecification\Filter\GreaterThan': + + return $this->getDqlFromGreaterThan($specification, $parameters); + case 'Happyr\DoctrineSpecification\Filter\In': + + return $this->getDqlFromIn($specification, $parameters); + case 'Happyr\DoctrineSpecification\Filter\IsNotNull': + + return $this->getDqlFromIsNotNull($specification, $parameters); + case 'Happyr\DoctrineSpecification\Filter\IsNull': + + return $this->getDqlFromIsNull($specification, $parameters); + case 'Happyr\DoctrineSpecification\Filter\LessOrEqualThan': + return $this->getDqlFromLessOrEqualThan($specification, $parameters); + + case 'Happyr\DoctrineSpecification\Filter\LessThan': + + return $this->getDqlFromLessThan($specification, $parameters); + case 'Happyr\DoctrineSpecification\Filter\Like': + + return $this->getDqlFromLike($specification, $parameters); + case 'Happyr\DoctrineSpecification\Filter\NotEquals': + + return $this->getDqlFromNotEquals($specification, $parameters); + case 'Happyr\DoctrineSpecification\Logic\AndX': + + return $this->getDqlFromAndX($specification, $parameters); + case 'Happyr\DoctrineSpecification\Logic\Not': + + return $this->getDqlFromNot($specification, $parameters); + case 'Happyr\DoctrineSpecification\Logic\OrX': + + return $this->getDqlFromOrX($specification, $parameters); + default: + throw new InvalidArgumentException(sprintf("Specification %s is not supported", get_class($specification))); + } + } + + private function getDqlFromIsNotNull(IsNotNull $filter) + { + return (string)($this->expression->isNotNull($filter->getField())); + } + + private function getDqlFromIsNull(IsNull $filter) + { + return (string)($this->expression->isNull($filter->getField())); + } + + private function getDqlFromEquals(Equals $filter, ParametersBag $parameters) + { + $parameters->add($filter->getValue()); + + return (string)($this->expression->eq($filter->getField(), $parameters->getLastName())); + } + + private function getDqlFromGreaterOrEqualThan(GreaterOrEqualThan $filter, ParametersBag $parameters) + { + $parameters->add($filter->getValue()); + + return (string)($this->expression->gte($filter->getField(), $parameters->getLastName())); + } + + private function getDqlFromNotEquals(NotEquals $filter, ParametersBag $parameters) + { + $parameters->add($filter->getValue()); + + return (string)($this->expression->neq($filter->getField(), $parameters->getLastName())); + } + + private function getDqlFromGreaterThan(GreaterThan $filter, ParametersBag $parameters) + { + $parameters->add($filter->getValue()); + + return (string)($this->expression->gt($filter->getField(), $parameters->getLastName())); + } + + private function getDqlFromLessOrEqualThan(LessOrEqualThan $filter, ParametersBag $parameters) + { + $parameters->add($filter->getValue()); + + return (string)($this->expression->lte($filter->getField(), $parameters->getLastName())); + } + + private function getDqlFromLessThan(LessThan $filter, ParametersBag $parameters) + { + $parameters->add($filter->getValue()); + + return (string)($this->expression->lt($filter->getField(), $parameters->getLastName())); + } + + private function getDqlFromIn(In $filter, ParametersBag $parameters) + { + $parameters->add($filter->getValue()); + + return (string)($this->expression->in($filter->getField(), $parameters->getLastName())); + } + + private function getDqlFromLike(Like $filter, ParametersBag $parameters) + { + /** @var $filter Like */ + $format = $filter->getFormat(); + $value = null; + if (Like::CONTAINS === $format) { + $value = "%" . $filter->getValue() . "%"; + } elseif (Like::STARTS_WITH === $format) { + $value = "%" . $filter->getValue(); + } elseif (Like::ENDS_WITH === $format) { + $value = $filter->getValue() . "%"; + } else { + throw new InvalidArgumentException(sprintf("Unsupported filter like format %s.", $format)); + } + $parameters->add($value); + + return (string)($this->expression->like($filter->getField(), $parameters->getLastName())); + } + + private function getDqlFromNot(Not $logic, ParametersBag $parameters) + { + $restriction = $this->getDQLPart($logic->getExpression(), $parameters); + return $this->expression->not($restriction); + } + + private function getDqlFromAndX(AndX $logic, ParametersBag $parameters) + { + $left = $this->getDQLPart($logic->getLeft(), $parameters); + $right = $this->getDQLPart($logic->getRight(), $parameters); + + return $this->expression->andX($left, $right); + } + + private function getDqlFromOrX(OrX $logic, ParametersBag $parameters) + { + $left = $this->getDQLPart($logic->getLeft(), $parameters); + $right = $this->getDQLPart($logic->getRight(), $parameters); + + return $this->expression->orX($left, $right); + } +} diff --git a/src/EntitySpecificationRepository.php b/src/EntitySpecificationRepository.php deleted file mode 100644 index e7db8f8f..00000000 --- a/src/EntitySpecificationRepository.php +++ /dev/null @@ -1,32 +0,0 @@ -createQueryBuilder($this->alias); - - $specification->modify($qb, $this->alias); - $query = $qb->where($specification->getFilter($qb, $this->alias))->getQuery(); - - if ($modifier instanceof Result\ResultModifier) { - $modifier->modify($query); - } - - return $query->execute(); - } -} diff --git a/src/Filter/Base/Comparison.php b/src/Filter/Base/Comparison.php new file mode 100644 index 00000000..172b5ab1 --- /dev/null +++ b/src/Filter/Base/Comparison.php @@ -0,0 +1,29 @@ +field = $field; + $this->value = $value; + } + + /** + * @inheritdoc + */ + public function getValue() + { + return $this->value; + } +} diff --git a/src/Filter/Base/Filter.php b/src/Filter/Base/Filter.php new file mode 100644 index 00000000..c999a292 --- /dev/null +++ b/src/Filter/Base/Filter.php @@ -0,0 +1,27 @@ +field = $field; + } + + /** + * @inheritdoc + */ + public function getField() + { + return $this->field; + } +} diff --git a/src/Filter/Base/FilterInterface.php b/src/Filter/Base/FilterInterface.php new file mode 100644 index 00000000..c7bed9d2 --- /dev/null +++ b/src/Filter/Base/FilterInterface.php @@ -0,0 +1,11 @@ +'; - const LT = '<'; - const LTE = '<='; - const GT = '>'; - const GTE = '>='; - const LIKE = 'LIKE'; - - private static $operators = array( - self::EQ, self::NEQ, - self::LT, self::LTE, - self::GT, self::GTE, - self::LIKE - ); - - /** - * @var string field - * - */ - protected $field; - - /** - * @var string value - * - */ - protected $value; - - /** - * @var string dqlAlias - * - */ - protected $dqlAlias; - /** - * @var string - */ - private $operator; - - /** - * Make sure the $field has a value equals to $value - * - * @param string $operator - * @param string $field - * @param string $value - * @param string $dqlAlias - * - * @throws InvalidArgumentException - */ - public function __construct($operator, $field, $value, $dqlAlias = null) - { - if (!in_array($operator, self::$operators)) { - throw new InvalidArgumentException( - sprintf('"%s" is not a valid comparison operator. Valid operators are: "%s"', - $operator, - implode(', ', self::$operators) - ) - ); - } - - $this->operator = $operator; - $this->field = $field; - $this->value = $value; - $this->dqlAlias = $dqlAlias; - } - - /** - * @param QueryBuilder $qb - * @param string $dqlAlias - * - * @return string - */ - public function getFilter(QueryBuilder $qb, $dqlAlias) - { - if ($this->dqlAlias !== null) { - $dqlAlias = $this->dqlAlias; - } - - $paramName = $this->getParameterName($qb); - $qb->setParameter($paramName, $this->value); - - return (string) new DoctrineComparison( - sprintf('%s.%s', $dqlAlias, $this->field), - $this->operator, - sprintf(':%s', $paramName) - ); - } - - /** - * Get a good unique parameter name - * - * @param QueryBuilder $qb - * - * @return string - */ - protected function getParameterName(QueryBuilder $qb) - { - return sprintf('comparison_%d', $qb->getParameters()->count()); - } -} diff --git a/src/Filter/Equals.php b/src/Filter/Equals.php index 4daeee91..fb56a89e 100644 --- a/src/Filter/Equals.php +++ b/src/Filter/Equals.php @@ -2,10 +2,8 @@ namespace Happyr\DoctrineSpecification\Filter; +use Happyr\DoctrineSpecification\Filter\Base\Comparison; + class Equals extends Comparison { - public function __construct($field, $value, $dqlAlias = null) - { - parent::__construct(self::EQ, $field, $value, $dqlAlias); - } } diff --git a/src/Filter/Filter.php b/src/Filter/Filter.php deleted file mode 100644 index c0d8f7ce..00000000 --- a/src/Filter/Filter.php +++ /dev/null @@ -1,16 +0,0 @@ -field = $field; - $this->value = $value; - $this->dqlAlias = $dqlAlias; - } - - - /** - * @param QueryBuilder $qb - * @param string $dqlAlias - * - * @return string - */ - public function getFilter(QueryBuilder $qb, $dqlAlias) - { - if ($this->dqlAlias !== null) { - $dqlAlias = $this->dqlAlias; - } - - $paramName = $this->getParameterName($qb); - $qb->setParameter($paramName, $this->value); - - return (string) $qb->expr()->in( - sprintf('%s.%s', $dqlAlias, $this->field), - sprintf(':%s', $paramName) - ); - } - - /** - * Get a good unique parameter name - * - * @param QueryBuilder $qb - * - * @return string - */ - protected function getParameterName(QueryBuilder $qb) - { - return sprintf('in_%d', $qb->getParameters()->count()); - } } diff --git a/src/Filter/IsNotNull.php b/src/Filter/IsNotNull.php index 1311e6f3..fbc3f27d 100644 --- a/src/Filter/IsNotNull.php +++ b/src/Filter/IsNotNull.php @@ -2,22 +2,8 @@ namespace Happyr\DoctrineSpecification\Filter; -use Doctrine\ORM\QueryBuilder; +use Happyr\DoctrineSpecification\Filter\Base\Filter; -class IsNotNull extends IsNull +class IsNotNull extends Filter { - /** - * @param QueryBuilder $qb - * @param string $dqlAlias - * - * @return string - */ - public function getFilter(QueryBuilder $qb, $dqlAlias) - { - if ($this->dqlAlias !== null) { - $dqlAlias = $this->dqlAlias; - } - - return (string) $qb->expr()->isNotNull(sprintf('%s.%s', $dqlAlias, $this->field)); - } -} \ No newline at end of file +} diff --git a/src/Filter/IsNull.php b/src/Filter/IsNull.php index 8e6646e6..b78376c3 100644 --- a/src/Filter/IsNull.php +++ b/src/Filter/IsNull.php @@ -2,42 +2,8 @@ namespace Happyr\DoctrineSpecification\Filter; -use Doctrine\ORM\QueryBuilder; +use Happyr\DoctrineSpecification\Filter\Base\Filter; -class IsNull implements Filter +class IsNull extends Filter { - /** - * @var string field - */ - protected $field; - - /** - * @var null|string dqlAlias - */ - protected $dqlAlias; - - /** - * @param string $field - * @param string|null $dqlAlias - */ - public function __construct($field, $dqlAlias = null) - { - $this->field = $field; - $this->dqlAlias = $dqlAlias; - } - - /** - * @param QueryBuilder $qb - * @param string $dqlAlias - * - * @return string - */ - public function getFilter(QueryBuilder $qb, $dqlAlias) - { - if ($this->dqlAlias !== null) { - $dqlAlias = $this->dqlAlias; - } - - return (string) $qb->expr()->isNull(sprintf('%s.%s', $dqlAlias, $this->field)); - } } diff --git a/src/Filter/LessOrEqualThan.php b/src/Filter/LessOrEqualThan.php index b479f2b9..72b203a4 100644 --- a/src/Filter/LessOrEqualThan.php +++ b/src/Filter/LessOrEqualThan.php @@ -2,10 +2,8 @@ namespace Happyr\DoctrineSpecification\Filter; +use Happyr\DoctrineSpecification\Filter\Base\Comparison; + class LessOrEqualThan extends Comparison { - public function __construct($field, $value, $dqlAlias = null) - { - parent::__construct(self::LTE, $field, $value, $dqlAlias); - } } diff --git a/src/Filter/LessThan.php b/src/Filter/LessThan.php index 6a87a2bd..be29e044 100644 --- a/src/Filter/LessThan.php +++ b/src/Filter/LessThan.php @@ -2,10 +2,8 @@ namespace Happyr\DoctrineSpecification\Filter; +use Happyr\DoctrineSpecification\Filter\Base\Comparison; + class LessThan extends Comparison { - public function __construct($field, $value, $dqlAlias = null) - { - parent::__construct(self::LT, $field, $value, $dqlAlias); - } } diff --git a/src/Filter/Like.php b/src/Filter/Like.php index 8fad640d..ad820a88 100644 --- a/src/Filter/Like.php +++ b/src/Filter/Like.php @@ -2,23 +2,30 @@ namespace Happyr\DoctrineSpecification\Filter; +use Happyr\DoctrineSpecification\Filter\Base\Comparison; + class Like extends Comparison { - const CONTAINS = "%%%s%%"; - const ENDS_WITH = "%%%s"; - const STARTS_WITH = "%s%%"; + const CONTAINS = 1; + const ENDS_WITH = 2; + const STARTS_WITH = 3; - public function __construct($field, $value, $format = self::CONTAINS, $dqlAlias = null) + /** + * @param string $field + * @param mixed $value + * @param int $format + */ + public function __construct($field, $value, $format = self::CONTAINS) { - $formattedValue = $this->formatValue($format, $value); - parent::__construct(self::LIKE, $field, $formattedValue, $dqlAlias); + parent::__construct($field, $value); + $this->format = $format; } /** - * @param string $format + * @return int */ - private function formatValue($format, $value) + public function getFormat() { - return sprintf($format, $value); + return $this->format; } } diff --git a/src/Filter/NotEquals.php b/src/Filter/NotEquals.php index 474b6716..dafc85be 100644 --- a/src/Filter/NotEquals.php +++ b/src/Filter/NotEquals.php @@ -2,10 +2,8 @@ namespace Happyr\DoctrineSpecification\Filter; +use Happyr\DoctrineSpecification\Filter\Base\Comparison; + class NotEquals extends Comparison { - public function __construct($field, $value, $dqlAlias = null) - { - parent::__construct(self::NEQ, $field, $value, $dqlAlias); - } } diff --git a/src/Logic/AndX.php b/src/Logic/AndX.php index 0d48de2c..a9411a7c 100644 --- a/src/Logic/AndX.php +++ b/src/Logic/AndX.php @@ -2,10 +2,40 @@ namespace Happyr\DoctrineSpecification\Logic; -class AndX extends LogicX + +use Happyr\DoctrineSpecification\Filter\Base\FilterInterface; + +class AndX implements LogicX { - function __construct() + private $left; + private $right; + + public function __construct(FilterInterface $left, FilterInterface $right) + { + $this->left = $left; + $this->right = $right; + } + + /** + * @return mixed + */ + public function getLeft() + { + return $this->left; + } + + /** + * @return mixed + */ + public function getRight() + { + return $this->right; + } + + /** + * @return mixed Return field name to filter + */ + public function getField() { - parent::__construct(self::AND_X, func_get_args()); } } diff --git a/src/Logic/LogicX.php b/src/Logic/LogicX.php index c7e9d07c..beb3a431 100644 --- a/src/Logic/LogicX.php +++ b/src/Logic/LogicX.php @@ -2,69 +2,8 @@ namespace Happyr\DoctrineSpecification\Logic; -use Doctrine\ORM\QueryBuilder; -use Happyr\DoctrineSpecification\Filter\Filter; -use Happyr\DoctrineSpecification\Specification; +use Happyr\DoctrineSpecification\Filter\Base\FilterInterface; -/** - * This class should be used when you combine two or more Expressions - */ -class LogicX implements Specification +interface LogicX extends FilterInterface { - const AND_X = 'andX'; - const OR_X = 'orX'; - - /** - * @var Filter[] children - */ - private $children; - - /** - * @var string - */ - private $expression; - - /** - * Take two or more Expression as parameters - * - * @param string $expression - * @param Filter[] $children - */ - public function __construct($expression, array $children) - { - $this->expression = $expression; - $this->children = $children; - } - - /** - * @param QueryBuilder $qb - * @param string $dqlAlias - * - * @return string - */ - public function getFilter(QueryBuilder $qb, $dqlAlias) - { - return call_user_func_array( - array($qb->expr(), $this->expression), - array_map( - function (Filter $expr) use ($qb, $dqlAlias) { - return $expr->getFilter($qb, $dqlAlias); - }, - $this->children - ) - ); - } - - /** - * @param QueryBuilder $query - * @param string $dqlAlias - */ - public function modify(QueryBuilder $query, $dqlAlias) - { - foreach ($this->children as $child) { - if ($child instanceof Specification) { - $child->modify($query, $dqlAlias); - } - } - } } diff --git a/src/Logic/Not.php b/src/Logic/Not.php index 9da50f36..acdef4e4 100644 --- a/src/Logic/Not.php +++ b/src/Logic/Not.php @@ -2,44 +2,36 @@ namespace Happyr\DoctrineSpecification\Logic; -use Doctrine\ORM\QueryBuilder; -use Happyr\DoctrineSpecification\Filter\Filter; -use Happyr\DoctrineSpecification\Specification; +use Happyr\DoctrineSpecification\Filter\Base\FilterInterface; +use Happyr\DoctrineSpecification\SpecificationInterface; -class Not implements Specification +class Not implements LogicX { /** - * @var Filter parent + * @var FilterInterface */ - private $parent; + private $expression; /** - * @param Filter $expr + * @param FilterInterface $expression */ - public function __construct(Filter $expr) + public function __construct(FilterInterface $expression) { - $this->parent = $expr; + $this->expression = $expression; } /** - * @param QueryBuilder $qb - * @param string $dqlAlias - * - * @return string + * @return SpecificationInterface */ - public function getFilter(QueryBuilder $qb, $dqlAlias) + public function getExpression() { - return (string) $qb->expr()->not($this->parent->getFilter($qb, $dqlAlias)); + return $this->expression; } /** - * @param QueryBuilder $query - * @param string $dqlAlias + * @return mixed Return field name to filter */ - public function modify(QueryBuilder $query, $dqlAlias) + public function getField() { - if ($this->parent instanceof Specification) { - $this->parent->modify($query, $dqlAlias); - } } } diff --git a/src/Logic/OrX.php b/src/Logic/OrX.php index 13cc36c2..85fb4662 100644 --- a/src/Logic/OrX.php +++ b/src/Logic/OrX.php @@ -2,10 +2,39 @@ namespace Happyr\DoctrineSpecification\Logic; -class OrX extends LogicX +use Happyr\DoctrineSpecification\Filter\Base\FilterInterface; + +class OrX implements LogicX { - function __construct() + private $left; + private $right; + + public function __construct(FilterInterface $left, FilterInterface $right) + { + $this->left = $left; + $this->right = $right; + } + + /** + * @return mixed + */ + public function getLeft() + { + return $this->left; + } + + /** + * @return mixed + */ + public function getRight() + { + return $this->right; + } + + /** + * @return mixed Return field name to filter + */ + public function getField() { - parent::__construct(self::OR_X, func_get_args()); } } diff --git a/src/ParametersBag.php b/src/ParametersBag.php new file mode 100644 index 00000000..59fa560e --- /dev/null +++ b/src/ParametersBag.php @@ -0,0 +1,67 @@ +parameters = []; + } + + /** + * Returns parameters array + * + * @return array + */ + public function getAll() + { + return $this->parameters; + } + + /** + * Add new parameter to collection and returns it's name + * + * @param $value mixed parameter value + * + * @return string DQL Parameter name + */ + public function add($value) + { + $key = count($this->parameters) + 1; + $this->parameters[$key] = $value; + + $this->lastName = '?' . $key; + } + + /** + * Checks whether the parameters array is non empty + * + * @return bool + */ + public function hasAny() + { + return (boolean)count($this->parameters); + } + + /** + * @return string + */ + public function getLastName() + { + return $this->lastName; + } +} diff --git a/src/Query/QueryModifier.php b/src/Query/QueryModifier.php index 25c1ff41..615eb4cd 100644 --- a/src/Query/QueryModifier.php +++ b/src/Query/QueryModifier.php @@ -6,10 +6,4 @@ interface QueryModifier { - /** - * @param QueryBuilder $qb - * @param string $dqlAlias - * @return void - */ - public function modify(QueryBuilder $qb, $dqlAlias); -} +} diff --git a/src/RepositoryFactory.php b/src/RepositoryFactory.php deleted file mode 100644 index 1d9c209a..00000000 --- a/src/RepositoryFactory.php +++ /dev/null @@ -1,31 +0,0 @@ -getClassMetadata($entityName) - ); - } -} diff --git a/src/Spec.php b/src/Spec.php deleted file mode 100644 index b071929a..00000000 --- a/src/Spec.php +++ /dev/null @@ -1,95 +0,0 @@ -expression = $expression; + } + + public function __construct(DoctrineTransformer $rootTransformer) + { + $this->rootTransformer = $rootTransformer; + } + + public function supports(FilterInterface $filter) + { + return $filter instanceof Not; + } + + /** + * Transform filter to DQL part + * @param FilterInterface $filter + * @param ParametersBag $parameters + * + * @return string + */ + public function transform(FilterInterface $filter, ParametersBag $parameters) + { + if ($filter instanceof Not) { + return $this->transformNot($filter); + } + } + + + private function transformNot(Not $filter) + { + return $this->expression->not($this->rootTransformer->transform($filter->getExpression())); + } +}