diff --git a/.travis.yml b/.travis.yml
index 88688609..54eb6bab 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,33 +1,46 @@
language: php
+services:
+ - mongodb
+
cache:
- directories:
- - $HOME/.composer/cache
+ directories:
+ - $HOME/.composer/cache
branches:
except:
- - /^analysis-.*$/
- - /^patch-.*$/
+ - /^analysis-.*$/
+ - /^patch-.*$/
php:
- - 5.4
- - 5.5
- - 5.6
- - 7.0
- - 7.1
- - hhvm
+ - 5.4
+ - 5.5
+ - 5.6
+ - 7.0
+ - 7.1
+ - hhvm
env:
- global:
- - TEST_COMMAND="composer test"
+ global:
+ - TEST_COMMAND="composer test"
matrix:
- fast_finish: true
- allow_failures:
- - php: hhvm
+ fast_finish: true
+ allow_failures:
+ - php: hhvm
+
+before_install:
+
+ - if [ ${TRAVIS_PHP_VERSION:0:2} == "5." ]; then yes '' | pecl -q install -f mongo; fi
+ - if [ ${TRAVIS_PHP_VERSION:0:2} == "7." ]; then pecl install -f mongodb; fi
+ - if [ ${TRAVIS_PHP_VERSION:0:2} == "7." ]; then composer require "alcaeus/mongo-php-adapter=^1.0.0" --ignore-platform-reqs; fi
+
+
+ - if [ "$TRAVIS_PHP_VERSION" != "hhvm" ]; then echo "memory_limit=2G" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; fi;
+ - if [ -n "$GH_TOKEN" ]; then composer config github-oauth.github.com ${GH_TOKEN}; fi;
install:
- travis_retry composer update ${COMPOSER_FLAGS} --prefer-dist --no-interaction
script:
- - $TEST_COMMAND
+ - $TEST_COMMAND
diff --git a/composer.json b/composer.json
index df10fc54..59cfed0a 100644
--- a/composer.json
+++ b/composer.json
@@ -13,14 +13,19 @@
{
"name": "Kacper Gunia",
"email": "kacper@gunia.me"
+ },
+ {
+ "name": "Peter Gribanov",
+ "email": "info@peter-gribanov.ru"
}
],
"require": {
- "php": ">=5.4",
- "doctrine/orm": ">=2.2.3"
+ "php": ">=5.4"
},
"require-dev": {
- "phpspec/phpspec": "~2.1"
+ "phpspec/phpspec": "~2.1",
+ "doctrine/orm": "~2.2",
+ "doctrine/mongodb-odm": "~1.0.0"
},
"autoload": {
"psr-4": {
diff --git a/src/BaseSpecification.php b/src/BaseSpecification.php
deleted file mode 100644
index 26829763..00000000
--- a/src/BaseSpecification.php
+++ /dev/null
@@ -1,79 +0,0 @@
-dqlAlias = $dqlAlias;
- }
-
- /**
- * @param QueryBuilder $qb
- * @param string $dqlAlias
- *
- * @return string
- */
- public function getFilter(QueryBuilder $qb, $dqlAlias)
- {
- $spec = $this->getSpec();
- if ($spec instanceof Filter) {
- return $spec->getFilter($qb, $this->getAlias($dqlAlias));
- }
-
- return;
- }
-
- /**
- * @param QueryBuilder $qb
- * @param string $dqlAlias
- */
- public function modify(QueryBuilder $qb, $dqlAlias)
- {
- $spec = $this->getSpec();
- if ($spec instanceof QueryModifier) {
- $spec->modify($qb, $this->getAlias($dqlAlias));
- }
- }
-
- /**
- * Return all the specifications.
- *
- * @return Specification
- */
- protected function getSpec()
- {
- return;
- }
-
- /**
- * @param string $dqlAlias
- *
- * @return string
- */
- private function getAlias($dqlAlias)
- {
- if ($this->dqlAlias !== null) {
- return $this->dqlAlias;
- }
-
- return $dqlAlias;
- }
-}
diff --git a/src/EntitySpecificationRepository.php b/src/EntitySpecificationRepository.php
deleted file mode 100644
index e5a96815..00000000
--- a/src/EntitySpecificationRepository.php
+++ /dev/null
@@ -1,15 +0,0 @@
-getQuery($specification, $modifier);
-
- return $query->execute();
- }
-
- /**
- * Get single result when you match with a Specification.
- *
- * @param Filter|QueryModifier $specification
- * @param ResultModifier $modifier
- *
- * @throw Exception\NonUniqueException If more than one result is found
- * @throw Exception\NoResultException If no results found
- *
- * @return mixed
- */
- public function matchSingleResult($specification, ResultModifier $modifier = null)
- {
- $query = $this->getQuery($specification, $modifier);
-
- try {
- return $query->getSingleResult();
- } catch (NonUniqueResultException $e) {
- throw new Exception\NonUniqueResultException($e->getMessage(), $e->getCode(), $e);
- } catch (NoResultException $e) {
- throw new Exception\NoResultException($e->getMessage(), $e->getCode(), $e);
- }
- }
-
- /**
- * Get single result or null when you match with a Specification.
- *
- * @param Filter|QueryModifier $specification
- * @param ResultModifier $modifier
- *
- * @throw Exception\NonUniqueException If more than one result is found
- *
- * @return mixed|null
- */
- public function matchOneOrNullResult($specification, ResultModifier $modifier = null)
- {
- try {
- return $this->matchSingleResult($specification, $modifier);
- } catch (Exception\NoResultException $e) {
- return;
- }
- }
-
- /**
- * Prepare a Query with a Specification.
- *
- * @param Filter|QueryModifier $specification
- * @param ResultModifier $modifier
- *
- * @return \Doctrine\ORM\Query
- */
- public function getQuery($specification, ResultModifier $modifier = null)
- {
- $qb = $this->createQueryBuilder($this->alias);
- $this->applySpecification($qb, $specification);
- $query = $qb->getQuery();
-
- if ($modifier !== null) {
- $modifier->modify($query);
- }
-
- return $query;
- }
-
- /**
- * @param string $alias
- *
- * @return $this
- */
- public function setAlias($alias)
- {
- $this->alias = $alias;
-
- return $this;
- }
-
- /**
- * @return string
- */
- public function getAlias()
- {
- return $this->alias;
- }
-
- /**
- * @param QueryBuilder $queryBuilder
- * @param Filter|QueryModifier $specification
- * @param string $alias
- *
- * @throws \InvalidArgumentException
- */
- protected function applySpecification(QueryBuilder $queryBuilder, $specification = null, $alias = null)
- {
- if (null === $specification) {
- return;
- }
-
- if (!$specification instanceof QueryModifier && !$specification instanceof Filter) {
- throw new \InvalidArgumentException(sprintf(
- 'Expected argument of type "%s" or "%s", "%s" given.',
- 'Happyr\DoctrineSpecification\Query\QueryModifier',
- 'Happyr\DoctrineSpecification\Filter\Filter',
- is_object($specification) ? get_class($specification) : gettype($specification)
- ));
- }
-
- if ($specification instanceof QueryModifier) {
- $specification->modify($queryBuilder, $alias ?: $this->getAlias());
- }
-
- if ($specification instanceof Filter
- && $filter = (string) $specification->getFilter($queryBuilder, $alias ?: $this->getAlias())
- ) {
- $queryBuilder->andWhere($filter);
- }
- }
-}
diff --git a/src/Exception/InvalidArgumentException.php b/src/Exception/InvalidArgumentException.php
index cff92b04..0b941ba0 100644
--- a/src/Exception/InvalidArgumentException.php
+++ b/src/Exception/InvalidArgumentException.php
@@ -1,7 +1,66 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
namespace Happyr\DoctrineSpecification\Exception;
class InvalidArgumentException extends \InvalidArgumentException
{
+ /**
+ * @param array $supported_formats
+ * @param string $format
+ *
+ * @return self
+ */
+ public static function invalidLikeFormat(array $supported_formats, $format)
+ {
+ return new self(sprintf(
+ '"%s" is not a valid format. Valid format are: "%s"',
+ $format,
+ implode(', ', $supported_formats)
+ ));
+ }
+
+ /**
+ * @param array $supported_types
+ * @param string $type
+ *
+ * @return self
+ */
+ public static function invalidJoinConditionType(array $supported_types, $type)
+ {
+ return new self(sprintf(
+ '"%s" is not a valid condition type. Valid condition type are: "%s"',
+ $type,
+ implode(', ', $supported_types)
+ ));
+ }
+
+ /**
+ * @return self
+ */
+ public static function joinRequireConditionAndConditionType()
+ {
+ return new self('Join specification must have a condition and condition type.');
+ }
+
+ /**
+ * @param array $supported_types
+ * @param string $type
+ *
+ * @return self
+ */
+ public static function invalidOrderType(array $supported_types, $type)
+ {
+ return new self(sprintf(
+ '"%s" is not a valid order. Valid order are: "%s"',
+ $type,
+ implode(', ', $supported_types)
+ ));
+ }
}
diff --git a/src/Exception/LogicException.php b/src/Exception/LogicException.php
deleted file mode 100644
index cf622b0c..00000000
--- a/src/Exception/LogicException.php
+++ /dev/null
@@ -1,7 +0,0 @@
-
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
namespace Happyr\DoctrineSpecification\Exception;
diff --git a/src/Exception/NonUniqueResultException.php b/src/Exception/NonUniqueResultException.php
index e7a533fe..9216c12b 100644
--- a/src/Exception/NonUniqueResultException.php
+++ b/src/Exception/NonUniqueResultException.php
@@ -1,4 +1,11 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
namespace Happyr\DoctrineSpecification\Exception;
diff --git a/src/Exception/UnexpectedResultException.php b/src/Exception/UnexpectedResultException.php
index 5242a20f..1c5dd85c 100644
--- a/src/Exception/UnexpectedResultException.php
+++ b/src/Exception/UnexpectedResultException.php
@@ -1,4 +1,11 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
namespace Happyr\DoctrineSpecification\Exception;
diff --git a/src/Filter/Comparison.php b/src/Filter/Comparison.php
index af73ba05..4a1e016b 100644
--- a/src/Filter/Comparison.php
+++ b/src/Filter/Comparison.php
@@ -1,114 +1,56 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
namespace Happyr\DoctrineSpecification\Filter;
-use Doctrine\ORM\QueryBuilder;
-use Doctrine\ORM\Query\Expr\Comparison as DoctrineComparison;
-use Happyr\DoctrineSpecification\Exception\InvalidArgumentException;
-use Happyr\DoctrineSpecification\ValueConverter;
-
/**
* Comparison class.
*
* This is used when you need to compare two values
*/
-class Comparison implements Filter
+abstract class Comparison implements Filter
{
- const EQ = '=';
- const NEQ = '<>';
- const LT = '<';
- const LTE = '<=';
- const GT = '>';
- const GTE = '>=';
- const LIKE = 'LIKE';
-
/**
* @var string field
*/
- protected $field;
+ private $field;
/**
* @var string value
*/
- protected $value;
-
- /**
- * @var string dqlAlias
- */
- protected $dqlAlias;
-
- /**
- * @var array
- */
- private static $operators = array(
- self::EQ, self::NEQ,
- self::LT, self::LTE,
- self::GT, self::GTE,
- self::LIKE,
- );
-
- /**
- * @var string
- */
- private $operator;
+ private $value;
/**
* 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)
+ public function __construct($field, $value)
{
- 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)
+ public function getField()
{
- if ($this->dqlAlias !== null) {
- $dqlAlias = $this->dqlAlias;
- }
-
- $paramName = $this->getParameterName($qb);
- $qb->setParameter($paramName, ValueConverter::convertToDatabaseValue($this->value, $qb));
-
- return (string) new DoctrineComparison(
- sprintf('%s.%s', $dqlAlias, $this->field),
- $this->operator,
- sprintf(':%s', $paramName)
- );
+ return $this->field;
}
/**
- * Get a good unique parameter name.
- *
- * @param QueryBuilder $qb
- *
* @return string
*/
- protected function getParameterName(QueryBuilder $qb)
+ public function getValue()
{
- return sprintf('comparison_%d', $qb->getParameters()->count());
+ return $this->value;
}
}
diff --git a/src/Filter/Equals.php b/src/Filter/Equals.php
index cc475f42..bac084a3 100644
--- a/src/Filter/Equals.php
+++ b/src/Filter/Equals.php
@@ -1,16 +1,14 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
namespace Happyr\DoctrineSpecification\Filter;
class Equals extends Comparison
{
- /**
- * @param string $field
- * @param string $value
- * @param string $dqlAlias
- */
- 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
index b6310bb6..ef372746 100644
--- a/src/Filter/Filter.php
+++ b/src/Filter/Filter.php
@@ -1,16 +1,16 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
namespace Happyr\DoctrineSpecification\Filter;
-use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\Specification;
-interface Filter
+interface Filter extends Specification
{
- /**
- * @param QueryBuilder $qb
- * @param string $dqlAlias
- *
- * @return string
- */
- public function getFilter(QueryBuilder $qb, $dqlAlias);
}
diff --git a/src/Filter/GreaterOrEqualThan.php b/src/Filter/GreaterOrEqualThan.php
index 0f86e4bb..8af097eb 100644
--- a/src/Filter/GreaterOrEqualThan.php
+++ b/src/Filter/GreaterOrEqualThan.php
@@ -1,16 +1,14 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
namespace Happyr\DoctrineSpecification\Filter;
class GreaterOrEqualThan extends Comparison
{
- /**
- * @param string $field
- * @param string $value
- * @param string $dqlAlias
- */
- public function __construct($field, $value, $dqlAlias = null)
- {
- parent::__construct(self::GTE, $field, $value, $dqlAlias);
- }
}
diff --git a/src/Filter/GreaterThan.php b/src/Filter/GreaterThan.php
index e52d0910..2deeaa66 100644
--- a/src/Filter/GreaterThan.php
+++ b/src/Filter/GreaterThan.php
@@ -1,16 +1,14 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
namespace Happyr\DoctrineSpecification\Filter;
class GreaterThan extends Comparison
{
- /**
- * @param string $field
- * @param string $value
- * @param string $dqlAlias
- */
- public function __construct($field, $value, $dqlAlias = null)
- {
- parent::__construct(self::GT, $field, $value, $dqlAlias);
- }
}
diff --git a/src/Filter/In.php b/src/Filter/In.php
index 6900b7c0..8834d0c6 100644
--- a/src/Filter/In.php
+++ b/src/Filter/In.php
@@ -1,80 +1,51 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
namespace Happyr\DoctrineSpecification\Filter;
-use Doctrine\ORM\QueryBuilder;
-use Happyr\DoctrineSpecification\ValueConverter;
-
class In implements Filter
{
/**
- * @var string field
- */
- protected $field;
-
- /**
- * @var mixed value
+ * @var string
*/
- protected $value;
+ private $field;
/**
- * @var string dqlAlias
+ * @var mixed
*/
- protected $dqlAlias;
+ private $value;
/**
* Make sure the $field has a value equals to $value.
*
* @param string $field
* @param mixed $value
- * @param string $dqlAlias
*/
- public function __construct($field, $value, $dqlAlias = null)
+ public function __construct($field, $value)
{
$this->field = $field;
$this->value = $value;
- $this->dqlAlias = $dqlAlias;
}
/**
- * @param QueryBuilder $qb
- * @param string $dqlAlias
- *
* @return string
*/
- public function getFilter(QueryBuilder $qb, $dqlAlias)
+ public function getField()
{
- if ($this->dqlAlias !== null) {
- $dqlAlias = $this->dqlAlias;
- }
-
- $value = $this->value;
- if (is_array($value)) {
- foreach ($value as $k => $v) {
- $value[$k] = ValueConverter::convertToDatabaseValue($v, $qb);
- }
- } else {
- $value = ValueConverter::convertToDatabaseValue($value, $qb);
- }
-
- $paramName = $this->getParameterName($qb);
- $qb->setParameter($paramName, $value);
-
- return (string) $qb->expr()->in(
- sprintf('%s.%s', $dqlAlias, $this->field),
- sprintf(':%s', $paramName)
- );
+ return $this->field;
}
/**
- * Get a good unique parameter name.
- *
- * @param QueryBuilder $qb
- *
- * @return string
+ * @return mixed
*/
- protected function getParameterName(QueryBuilder $qb)
+ public function getValue()
{
- return sprintf('in_%d', $qb->getParameters()->count());
+ return $this->value;
}
}
diff --git a/src/Filter/InstanceOfX.php b/src/Filter/InstanceOfX.php
index a84001b6..7799ef12 100644
--- a/src/Filter/InstanceOfX.php
+++ b/src/Filter/InstanceOfX.php
@@ -1,43 +1,34 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
namespace Happyr\DoctrineSpecification\Filter;
-use Doctrine\ORM\QueryBuilder;
-
class InstanceOfX implements Filter
{
/**
- * @var null|string dqlAlias
+ * @var string
*/
- protected $dqlAlias;
+ private $value;
/**
- * @var string value
+ * @param string $value
*/
- protected $value;
-
- /**
- * @param string $value
- * @param string|null $dqlAlias
- */
- public function __construct($value, $dqlAlias = null)
+ public function __construct($value)
{
- $this->dqlAlias = $dqlAlias;
$this->value = $value;
}
/**
- * @param QueryBuilder $qb
- * @param string $dqlAlias
- *
* @return string
*/
- public function getFilter(QueryBuilder $qb, $dqlAlias)
+ public function getValue()
{
- if ($this->dqlAlias !== null) {
- $dqlAlias = $this->dqlAlias;
- }
-
- return sprintf('%s INSTANCE OF %s', $dqlAlias, $this->value);
+ return $this->value;
}
}
diff --git a/src/Filter/IsNotNull.php b/src/Filter/IsNotNull.php
index 9455bab3..89bdc5c0 100644
--- a/src/Filter/IsNotNull.php
+++ b/src/Filter/IsNotNull.php
@@ -1,23 +1,34 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
namespace Happyr\DoctrineSpecification\Filter;
-use Doctrine\ORM\QueryBuilder;
-
-class IsNotNull extends IsNull
+class IsNotNull implements Filter
{
/**
- * @param QueryBuilder $qb
- * @param string $dqlAlias
- *
- * @return string
+ * @var string
+ */
+ protected $field;
+
+ /**
+ * @param string $field
*/
- public function getFilter(QueryBuilder $qb, $dqlAlias)
+ public function __construct($field)
{
- if ($this->dqlAlias !== null) {
- $dqlAlias = $this->dqlAlias;
- }
+ $this->field = $field;
+ }
- return (string) $qb->expr()->isNotNull(sprintf('%s.%s', $dqlAlias, $this->field));
+ /**
+ * @return string
+ */
+ public function getField()
+ {
+ return $this->field;
}
}
diff --git a/src/Filter/IsNull.php b/src/Filter/IsNull.php
index ac824582..1d28db1b 100644
--- a/src/Filter/IsNull.php
+++ b/src/Filter/IsNull.php
@@ -1,43 +1,34 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
namespace Happyr\DoctrineSpecification\Filter;
-use Doctrine\ORM\QueryBuilder;
-
class IsNull implements Filter
{
/**
- * @var string field
+ * @var string
*/
protected $field;
/**
- * @var null|string dqlAlias
+ * @param string $field
*/
- protected $dqlAlias;
-
- /**
- * @param string $field
- * @param string|null $dqlAlias
- */
- public function __construct($field, $dqlAlias = null)
+ public function __construct($field)
{
$this->field = $field;
- $this->dqlAlias = $dqlAlias;
}
/**
- * @param QueryBuilder $qb
- * @param string $dqlAlias
- *
* @return string
*/
- public function getFilter(QueryBuilder $qb, $dqlAlias)
+ public function getField()
{
- if ($this->dqlAlias !== null) {
- $dqlAlias = $this->dqlAlias;
- }
-
- return (string) $qb->expr()->isNull(sprintf('%s.%s', $dqlAlias, $this->field));
+ return $this->field;
}
}
diff --git a/src/Filter/LessOrEqualThan.php b/src/Filter/LessOrEqualThan.php
index a8d2176e..c0364559 100644
--- a/src/Filter/LessOrEqualThan.php
+++ b/src/Filter/LessOrEqualThan.php
@@ -1,16 +1,14 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
namespace Happyr\DoctrineSpecification\Filter;
class LessOrEqualThan extends Comparison
{
- /**
- * @param string $field
- * @param string $value
- * @param string $dqlAlias
- */
- 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 cd2b97f6..e38213ff 100644
--- a/src/Filter/LessThan.php
+++ b/src/Filter/LessThan.php
@@ -1,16 +1,14 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
namespace Happyr\DoctrineSpecification\Filter;
class LessThan extends Comparison
{
- /**
- * @param string $field
- * @param string $value
- * @param string $dqlAlias
- */
- 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 4c94c4ee..73c4e4c7 100644
--- a/src/Filter/Like.php
+++ b/src/Filter/Like.php
@@ -1,33 +1,56 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
namespace Happyr\DoctrineSpecification\Filter;
+use Happyr\DoctrineSpecification\Exception\InvalidArgumentException;
+
class Like extends Comparison
{
- const CONTAINS = '%%%s%%';
- const ENDS_WITH = '%%%s';
- const STARTS_WITH = '%s%%';
+ const ENDS_WITH = 1;
+ const STARTS_WITH = 2;
+ const CONTAINS = 3; // self::ENDS_WITH | self::STARTS_WITH
+
+ /**
+ * @var int
+ */
+ private $format;
+
+ /**
+ * @var array
+ */
+ private static $formats = [
+ self::ENDS_WITH,
+ self::STARTS_WITH,
+ self::CONTAINS,
+ ];
/**
* @param string $field
* @param string $value
- * @param string $format
- * @param string $dqlAlias
+ * @param int $format
*/
- public function __construct($field, $value, $format = self::CONTAINS, $dqlAlias = null)
+ public function __construct($field, $value, $format = self::CONTAINS)
{
- $formattedValue = $this->formatValue($format, $value);
- parent::__construct(self::LIKE, $field, $formattedValue, $dqlAlias);
+ if (!in_array($format, self::$formats)) {
+ throw InvalidArgumentException::invalidLikeFormat(self::$formats, $format);
+ }
+
+ $this->format = $format;
+ parent::__construct($field, $value);
}
/**
- * @param string $format
- * @param string $value
- *
- * @return string
+ * @return int
*/
- private function formatValue($format, $value)
+ public function getFormat()
{
- return sprintf($format, $value);
+ return $this->format;
}
}
diff --git a/src/Filter/Logic/AndX.php b/src/Filter/Logic/AndX.php
new file mode 100644
index 00000000..f5036539
--- /dev/null
+++ b/src/Filter/Logic/AndX.php
@@ -0,0 +1,59 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Filter\Logic;
+
+use Happyr\DoctrineSpecification\Filter\Filter;
+
+class AndX implements Filter
+{
+ /**
+ * @var Filter[]
+ */
+ private $filters;
+
+ /**
+ * Construct it with two or more instances of Specification.
+ *
+ * @param Filter $filter1
+ * @param Filter $filter2
+ */
+ public function __construct(Filter $filter1, Filter $filter2)
+ {
+ foreach (func_get_args() as $filter) {
+ $this->andX($filter);
+ }
+ }
+
+ /**
+ * Append an other specification with a logic AND.
+ *
+ *
+ * $spec = new AndX(A, B);
+ * $spec->andX(C);
+ *
+ * // We be the same as
+ * $spec = new AndX(A, B, C);
+ *
+ *
+ * @param Filter $filter
+ */
+ public function andX(Filter $filter)
+ {
+ $this->filters[] = $filter;
+ }
+
+ /**
+ * @return Filter[]
+ */
+ public function getFilters()
+ {
+ return $this->filters;
+ }
+}
diff --git a/src/Filter/Logic/Not.php b/src/Filter/Logic/Not.php
new file mode 100644
index 00000000..575e50b7
--- /dev/null
+++ b/src/Filter/Logic/Not.php
@@ -0,0 +1,36 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Filter\Logic;
+
+use Happyr\DoctrineSpecification\Filter\Filter;
+
+class Not implements Filter
+{
+ /**
+ * @var Filter
+ */
+ private $filter;
+
+ /**
+ * @param Filter $filter
+ */
+ public function __construct(Filter $filter)
+ {
+ $this->filter = $filter;
+ }
+
+ /**
+ * @return Filter
+ */
+ public function getFilter()
+ {
+ return $this->filter;
+ }
+}
diff --git a/src/Filter/Logic/OrX.php b/src/Filter/Logic/OrX.php
new file mode 100644
index 00000000..fea19f20
--- /dev/null
+++ b/src/Filter/Logic/OrX.php
@@ -0,0 +1,59 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Filter\Logic;
+
+use Happyr\DoctrineSpecification\Filter\Filter;
+
+class OrX implements Filter
+{
+ /**
+ * @var Filter[]
+ */
+ private $filters;
+
+ /**
+ * Construct it with two or more instances of Specification.
+ *
+ * @param Filter $filter1
+ * @param Filter $filter2
+ */
+ public function __construct(Filter $filter1, Filter $filter2)
+ {
+ foreach (func_get_args() as $filter) {
+ $this->orX($filter);
+ }
+ }
+
+ /**
+ * Append an other specification with a logic OR.
+ *
+ *
+ * $spec = new OrX(A, B);
+ * $spec->orX(C);
+ *
+ * // We be the same as
+ * $spec = new OrX(A, B, C);
+ *
+ *
+ * @param Filter $filter
+ */
+ public function orX(Filter $filter)
+ {
+ $this->filters[] = $filter;
+ }
+
+ /**
+ * @return Filter[]
+ */
+ public function getFilters()
+ {
+ return $this->filters;
+ }
+}
diff --git a/src/Filter/NotEquals.php b/src/Filter/NotEquals.php
index 1d210a7f..a54b19db 100644
--- a/src/Filter/NotEquals.php
+++ b/src/Filter/NotEquals.php
@@ -1,16 +1,14 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
namespace Happyr\DoctrineSpecification\Filter;
class NotEquals extends Comparison
{
- /**
- * @param string $field
- * @param string $value
- * @param string $dqlAlias
- */
- 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
deleted file mode 100644
index 3b6e558f..00000000
--- a/src/Logic/AndX.php
+++ /dev/null
@@ -1,29 +0,0 @@
-
- * $spec = Spec::andX(A, B);
- * $spec->andX(C);
- *
- * // We be the same as
- * $spec = Spec::andX(A, B, C);
- *
- *
- * @param |Happyr\DoctrineSpecification\Filter\Filter|\Happyr\DoctrineSpecification\Query\QueryModifier $child
- */
- public function andX($child)
- {
- $this->append($child);
- }
-}
diff --git a/src/Logic/LogicX.php b/src/Logic/LogicX.php
deleted file mode 100644
index 17635de4..00000000
--- a/src/Logic/LogicX.php
+++ /dev/null
@@ -1,83 +0,0 @@
-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 ($spec) use ($qb, $dqlAlias) {
- if ($spec instanceof Filter) {
- return $spec->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 QueryModifier) {
- $child->modify($query, $dqlAlias);
- }
- }
- }
-
- /**
- * Add another child to this logic tree.
- *
- * @param |Happyr\DoctrineSpecification\Filter\Filter|\Happyr\DoctrineSpecification\Query\QueryModifier $child
- */
- protected function append($child)
- {
- $this->children[] = $child;
- }
-}
diff --git a/src/Logic/Not.php b/src/Logic/Not.php
deleted file mode 100644
index 1e7a9734..00000000
--- a/src/Logic/Not.php
+++ /dev/null
@@ -1,46 +0,0 @@
-child = $expr;
- }
-
- /**
- * @param QueryBuilder $qb
- * @param string $dqlAlias
- *
- * @return string
- */
- public function getFilter(QueryBuilder $qb, $dqlAlias)
- {
- return (string) $qb->expr()->not($this->child->getFilter($qb, $dqlAlias));
- }
-
- /**
- * @param QueryBuilder $query
- * @param string $dqlAlias
- */
- public function modify(QueryBuilder $query, $dqlAlias)
- {
- if ($this->child instanceof QueryModifier) {
- $this->child->modify($query, $dqlAlias);
- }
- }
-}
diff --git a/src/Logic/OrX.php b/src/Logic/OrX.php
deleted file mode 100644
index a5ae7ccd..00000000
--- a/src/Logic/OrX.php
+++ /dev/null
@@ -1,29 +0,0 @@
-
- * $spec = Spec::orX(A, B);
- * $spec->orX(C);
- *
- * // We be the same as
- * $spec = Spec::orX(A, B, C);
- *
- *
- * @param |Happyr\DoctrineSpecification\Filter\Filter|\Happyr\DoctrineSpecification\Query\QueryModifier $child
- */
- public function orX($child)
- {
- $this->append($child);
- }
-}
diff --git a/src/Query/AbstractJoin.php b/src/Query/AbstractJoin.php
deleted file mode 100644
index 19b829e5..00000000
--- a/src/Query/AbstractJoin.php
+++ /dev/null
@@ -1,59 +0,0 @@
-field = $field;
- $this->newAlias = $newAlias;
- $this->dqlAlias = $dqlAlias;
- }
-
- /**
- * @param QueryBuilder $qb
- * @param string $dqlAlias
- */
- public function modify(QueryBuilder $qb, $dqlAlias)
- {
- if ($this->dqlAlias !== null) {
- $dqlAlias = $this->dqlAlias;
- }
-
- $join = $this->getJoinType();
- $qb->$join(sprintf('%s.%s', $dqlAlias, $this->field), $this->newAlias);
- }
-
- /**
- * Return a join type (ie a function of QueryBuilder) like: "join", "innerJoin", "leftJoin".
- *
- * @return string
- */
- abstract protected function getJoinType();
-}
diff --git a/src/Query/GroupBy.php b/src/Query/GroupBy.php
deleted file mode 100644
index 2dcc7c2d..00000000
--- a/src/Query/GroupBy.php
+++ /dev/null
@@ -1,40 +0,0 @@
-field = $field;
- $this->dqlAlias = $dqlAlias;
- }
-
- /**
- * @param QueryBuilder $qb
- * @param string $dqlAlias
- */
- public function modify(QueryBuilder $qb, $dqlAlias)
- {
- if ($this->dqlAlias !== null) {
- $dqlAlias = $this->dqlAlias;
- }
- $qb->addGroupBy(sprintf('%s.%s', $dqlAlias, $this->field));
- }
-}
diff --git a/src/Query/InnerJoin.php b/src/Query/InnerJoin.php
deleted file mode 100644
index 2915bdbc..00000000
--- a/src/Query/InnerJoin.php
+++ /dev/null
@@ -1,14 +0,0 @@
-limit = $limit;
- }
-
- /**
- * @param QueryBuilder $qb
- * @param string $dqlAlias
- */
- public function modify(QueryBuilder $qb, $dqlAlias)
- {
- $qb->setMaxResults($this->limit);
- }
-}
diff --git a/src/Query/Offset.php b/src/Query/Offset.php
deleted file mode 100644
index 12b8913b..00000000
--- a/src/Query/Offset.php
+++ /dev/null
@@ -1,30 +0,0 @@
-offset = $offset;
- }
-
- /**
- * @param QueryBuilder $qb
- * @param string $dqlAlias
- */
- public function modify(QueryBuilder $qb, $dqlAlias)
- {
- $qb->setFirstResult($this->offset);
- }
-}
diff --git a/src/Query/OrderBy.php b/src/Query/OrderBy.php
deleted file mode 100644
index 23766eef..00000000
--- a/src/Query/OrderBy.php
+++ /dev/null
@@ -1,48 +0,0 @@
-field = $field;
- $this->order = $order;
- $this->dqlAlias = $dqlAlias;
- }
-
- /**
- * @param QueryBuilder $qb
- * @param string $dqlAlias
- */
- public function modify(QueryBuilder $qb, $dqlAlias)
- {
- if ($this->dqlAlias !== null) {
- $dqlAlias = $this->dqlAlias;
- }
-
- $qb->addOrderBy(sprintf('%s.%s', $dqlAlias, $this->field), $this->order);
- }
-}
diff --git a/src/Query/QueryModifier.php b/src/Query/QueryModifier.php
deleted file mode 100644
index 66e41d40..00000000
--- a/src/Query/QueryModifier.php
+++ /dev/null
@@ -1,14 +0,0 @@
-children = func_get_args();
- }
-
- /**
- * @param QueryBuilder $qb
- * @param string $dqlAlias
- */
- public function modify(QueryBuilder $qb, $dqlAlias)
- {
- foreach ($this->children as $child) {
- if (!$child instanceof QueryModifier) {
- throw new InvalidArgumentException(
- sprintf(
- 'Child passed to QueryModifierCollection must be an instance of Happyr\DoctrineSpecification\Query\QueryModifier, but instance of %s found',
- get_class($child)
- )
- );
- }
-
- $child->modify($qb, $dqlAlias);
- }
- }
-}
diff --git a/src/Query/Slice.php b/src/Query/Slice.php
deleted file mode 100644
index bd75aa07..00000000
--- a/src/Query/Slice.php
+++ /dev/null
@@ -1,41 +0,0 @@
-sliceSize = $sliceSize;
- $this->sliceNumber = $sliceNumber;
- }
-
- /**
- * @param QueryBuilder $qb
- * @param string $dqlAlias
- */
- public function modify(QueryBuilder $qb, $dqlAlias)
- {
- $qb->setMaxResults($this->sliceSize);
-
- if ($this->sliceNumber > 0) {
- $qb->setFirstResult($this->sliceNumber * $this->sliceSize);
- }
- }
-}
diff --git a/src/QueryModifier/AbstractJoin.php b/src/QueryModifier/AbstractJoin.php
new file mode 100644
index 00000000..99610808
--- /dev/null
+++ b/src/QueryModifier/AbstractJoin.php
@@ -0,0 +1,101 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\QueryModifier;
+
+use Happyr\DoctrineSpecification\Exception\InvalidArgumentException;
+use Happyr\DoctrineSpecification\Filter\Filter;
+
+abstract class AbstractJoin implements QueryModifier
+{
+ const ON = 'ON';
+ const WITH = 'WITH';
+
+ /**
+ * @var string
+ */
+ private $field;
+
+ /**
+ * @var string
+ */
+ private $alias;
+
+ /**
+ * @var Filter|null
+ */
+ private $condition;
+
+ /**
+ * @var int|null
+ */
+ private $conditionType;
+
+ /**
+ * @var array
+ */
+ private static $conditionTypes = [
+ self::ON,
+ self::WITH,
+ ];
+
+ /**
+ * @param string $field
+ * @param string $alias
+ * @param int|null $conditionType
+ * @param Filter|null $condition
+ */
+ public function __construct($field, $alias, $conditionType = null, Filter $condition = null)
+ {
+ if ($conditionType && !in_array($conditionType, self::$conditionTypes)) {
+ throw InvalidArgumentException::invalidJoinConditionType(self::$conditionTypes, $conditionType);
+ }
+
+ if ((!$conditionType && $condition) || ($conditionType && !$condition)) {
+ throw InvalidArgumentException::joinRequireConditionAndConditionType();
+ }
+
+ $this->field = $field;
+ $this->alias = $alias;
+ $this->condition = $condition;
+ $this->conditionType = $conditionType;
+ }
+
+ /**
+ * @return string
+ */
+ public function getField()
+ {
+ return $this->field;
+ }
+
+ /**
+ * @return string
+ */
+ public function getAlias()
+ {
+ return $this->alias;
+ }
+
+ /**
+ * @return Filter|null
+ */
+ public function getCondition()
+ {
+ return $this->condition;
+ }
+
+ /**
+ * @return int|null
+ */
+ public function getConditionType()
+ {
+ return $this->conditionType;
+ }
+}
diff --git a/src/QueryModifier/GroupBy.php b/src/QueryModifier/GroupBy.php
new file mode 100644
index 00000000..6652db67
--- /dev/null
+++ b/src/QueryModifier/GroupBy.php
@@ -0,0 +1,34 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\QueryModifier;
+
+class GroupBy implements QueryModifier
+{
+ /**
+ * @var string
+ */
+ private $field;
+
+ /**
+ * @param string $field
+ */
+ public function __construct($field)
+ {
+ $this->field = $field;
+ }
+
+ /**
+ * @return string
+ */
+ public function getField()
+ {
+ return $this->field;
+ }
+}
diff --git a/src/QueryModifier/Having.php b/src/QueryModifier/Having.php
new file mode 100644
index 00000000..0142b22b
--- /dev/null
+++ b/src/QueryModifier/Having.php
@@ -0,0 +1,36 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\QueryModifier;
+
+use Happyr\DoctrineSpecification\Filter\Filter;
+
+class Having implements QueryModifier
+{
+ /**
+ * @var Filter child
+ */
+ private $filter;
+
+ /**
+ * @param Filter $filter
+ */
+ public function __construct(Filter $filter)
+ {
+ $this->filter = $filter;
+ }
+
+ /**
+ * @return Filter
+ */
+ public function getFilter()
+ {
+ return $this->filter;
+ }
+}
diff --git a/src/QueryModifier/InnerJoin.php b/src/QueryModifier/InnerJoin.php
new file mode 100644
index 00000000..10bd3bd7
--- /dev/null
+++ b/src/QueryModifier/InnerJoin.php
@@ -0,0 +1,14 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\QueryModifier;
+
+class InnerJoin extends AbstractJoin
+{
+}
diff --git a/src/QueryModifier/Join.php b/src/QueryModifier/Join.php
new file mode 100644
index 00000000..1428d664
--- /dev/null
+++ b/src/QueryModifier/Join.php
@@ -0,0 +1,14 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\QueryModifier;
+
+class Join extends AbstractJoin
+{
+}
diff --git a/src/QueryModifier/LeftJoin.php b/src/QueryModifier/LeftJoin.php
new file mode 100644
index 00000000..08435069
--- /dev/null
+++ b/src/QueryModifier/LeftJoin.php
@@ -0,0 +1,14 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\QueryModifier;
+
+class LeftJoin extends AbstractJoin
+{
+}
diff --git a/src/QueryModifier/Map.php b/src/QueryModifier/Map.php
new file mode 100644
index 00000000..83ddcf1e
--- /dev/null
+++ b/src/QueryModifier/Map.php
@@ -0,0 +1,18 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\QueryModifier;
+
+interface Map extends QueryModifier
+{
+ /**
+ * @return string
+ */
+ public function getMap();
+}
diff --git a/src/QueryModifier/QueryModifier.php b/src/QueryModifier/QueryModifier.php
new file mode 100644
index 00000000..7d6ec179
--- /dev/null
+++ b/src/QueryModifier/QueryModifier.php
@@ -0,0 +1,16 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\QueryModifier;
+
+use Happyr\DoctrineSpecification\Specification;
+
+interface QueryModifier extends Specification
+{
+}
diff --git a/src/QueryModifier/QueryModifierCollection.php b/src/QueryModifier/QueryModifierCollection.php
new file mode 100644
index 00000000..2a7f3389
--- /dev/null
+++ b/src/QueryModifier/QueryModifierCollection.php
@@ -0,0 +1,47 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\QueryModifier;
+
+class QueryModifierCollection implements QueryModifier
+{
+ /**
+ * @var QueryModifier[]
+ */
+ private $modifiers;
+
+ /**
+ * Construct it with two or more instances of QueryModifier.
+ *
+ * @param QueryModifier $modifier1
+ * @param QueryModifier $modifier2
+ */
+ public function __construct(QueryModifier $modifier1, QueryModifier $modifier2)
+ {
+ foreach (func_get_args() as $modifier) {
+ $this->addModifier($modifier);
+ }
+ }
+
+ /**
+ * @param QueryModifier $modifier
+ */
+ public function addModifier(QueryModifier $modifier)
+ {
+ $this->modifiers[] = $modifier;
+ }
+
+ /**
+ * @return QueryModifier[]
+ */
+ public function getModifiers()
+ {
+ return $this->modifiers;
+ }
+}
diff --git a/src/QueryModifier/Reduce.php b/src/QueryModifier/Reduce.php
new file mode 100644
index 00000000..5ff8aa9f
--- /dev/null
+++ b/src/QueryModifier/Reduce.php
@@ -0,0 +1,18 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\QueryModifier;
+
+interface Reduce extends QueryModifier
+{
+ /**
+ * @return string
+ */
+ public function getReduce();
+}
diff --git a/src/Result/AsArray.php b/src/Result/AsArray.php
deleted file mode 100644
index 60b3f466..00000000
--- a/src/Result/AsArray.php
+++ /dev/null
@@ -1,20 +0,0 @@
-setHydrationMode(Query::HYDRATE_ARRAY);
- }
-}
diff --git a/src/Result/AsSingleScalar.php b/src/Result/AsSingleScalar.php
deleted file mode 100644
index 6fd30190..00000000
--- a/src/Result/AsSingleScalar.php
+++ /dev/null
@@ -1,20 +0,0 @@
-setHydrationMode(Query::HYDRATE_SINGLE_SCALAR);
- }
-}
diff --git a/src/Result/ResultModifier.php b/src/Result/ResultModifier.php
deleted file mode 100644
index c07df6ef..00000000
--- a/src/Result/ResultModifier.php
+++ /dev/null
@@ -1,13 +0,0 @@
-children = func_get_args();
- }
-
- /**
- * @param AbstractQuery $query
- */
- public function modify(AbstractQuery $query)
- {
- foreach ($this->children as $child) {
- if (!$child instanceof ResultModifier) {
- throw new InvalidArgumentException(
- sprintf(
- 'Child passed to ResultModifierCollection must be an instance of Happyr\DoctrineSpecification\Result\ResultModifier, but instance of %s found',
- get_class($child)
- )
- );
- }
-
- $child->modify($query);
- }
- }
-}
diff --git a/src/Result/RoundDateTime.php b/src/Result/RoundDateTime.php
deleted file mode 100644
index d9eae48c..00000000
--- a/src/Result/RoundDateTime.php
+++ /dev/null
@@ -1,42 +0,0 @@
-roundSeconds = $roundSeconds;
- }
-
- /**
- * @param AbstractQuery $query
- */
- public function modify(AbstractQuery $query)
- {
- foreach ($query->getParameters() as $parameter) {
- /* @var $parameter Parameter */
- if ($parameter->getValue() instanceof \DateTimeInterface) {
- // round down so that the results do not include data that should not be there.
- $date = clone $parameter->getValue();
- $date = $date->setTimestamp(floor($date->getTimestamp() / $this->roundSeconds) * $this->roundSeconds);
-
- $query->setParameter($parameter->getName(), $date, $parameter->getType());
- }
- }
- }
-}
diff --git a/src/ResultManagement/CountOf.php b/src/ResultManagement/CountOf.php
new file mode 100644
index 00000000..abc64d09
--- /dev/null
+++ b/src/ResultManagement/CountOf.php
@@ -0,0 +1,16 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\ResultManagement;
+
+use Happyr\DoctrineSpecification\Specification;
+
+class CountOf implements Specification
+{
+}
diff --git a/src/ResultManagement/Limit.php b/src/ResultManagement/Limit.php
new file mode 100644
index 00000000..bdf98bf7
--- /dev/null
+++ b/src/ResultManagement/Limit.php
@@ -0,0 +1,36 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\ResultManagement;
+
+use Happyr\DoctrineSpecification\Specification;
+
+class Limit implements Specification
+{
+ /**
+ * @var int
+ */
+ private $limit;
+
+ /**
+ * @param int $limit
+ */
+ public function __construct($limit)
+ {
+ $this->limit = $limit;
+ }
+
+ /**
+ * @return int
+ */
+ public function getLimit()
+ {
+ return $this->limit;
+ }
+}
diff --git a/src/ResultManagement/Offset.php b/src/ResultManagement/Offset.php
new file mode 100644
index 00000000..23a7f8f4
--- /dev/null
+++ b/src/ResultManagement/Offset.php
@@ -0,0 +1,36 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\ResultManagement;
+
+use Happyr\DoctrineSpecification\Specification;
+
+class Offset implements Specification
+{
+ /**
+ * @var int
+ */
+ private $offset;
+
+ /**
+ * @param int $offset
+ */
+ public function __construct($offset)
+ {
+ $this->offset = $offset;
+ }
+
+ /**
+ * @return int
+ */
+ public function getOffset()
+ {
+ return $this->offset;
+ }
+}
diff --git a/src/ResultManagement/OrderBy.php b/src/ResultManagement/OrderBy.php
new file mode 100644
index 00000000..5d1b3411
--- /dev/null
+++ b/src/ResultManagement/OrderBy.php
@@ -0,0 +1,67 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\ResultManagement;
+
+use Happyr\DoctrineSpecification\Exception\InvalidArgumentException;
+use Happyr\DoctrineSpecification\Specification;
+
+class OrderBy implements Specification
+{
+ const ASC = 'ASC';
+ const DESC = 'DESC';
+
+ /**
+ * @var string
+ */
+ private $field;
+
+ /**
+ * @var array
+ */
+ private static $orders = [
+ self::ASC,
+ self::DESC,
+ ];
+
+ /**
+ * @var string
+ */
+ private $order;
+
+ /**
+ * @param string $field
+ * @param string $order
+ */
+ public function __construct($field, $order = self::ASC)
+ {
+ if (!in_array($order, self::$orders)) {
+ throw InvalidArgumentException::invalidOrderType(self::$orders, $order);
+ }
+
+ $this->field = $field;
+ $this->order = $order;
+ }
+
+ /**
+ * @return string
+ */
+ public function getField()
+ {
+ return $this->field;
+ }
+
+ /**
+ * @return string
+ */
+ public function getOrder()
+ {
+ return $this->order;
+ }
+}
diff --git a/src/ResultManagement/Slice.php b/src/ResultManagement/Slice.php
new file mode 100644
index 00000000..949ab2fb
--- /dev/null
+++ b/src/ResultManagement/Slice.php
@@ -0,0 +1,51 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\ResultManagement;
+
+use Happyr\DoctrineSpecification\Specification;
+
+class Slice implements Specification
+{
+ /**
+ * @var int
+ */
+ private $sliceSize;
+
+ /**
+ * @var int
+ */
+ private $sliceNumber = 0;
+
+ /**
+ * @param int $sliceSize
+ * @param int $sliceNumber
+ */
+ public function __construct($sliceSize, $sliceNumber = 0)
+ {
+ $this->sliceSize = $sliceSize;
+ $this->sliceNumber = $sliceNumber;
+ }
+
+ /**
+ * @return int
+ */
+ public function getSliceSize()
+ {
+ return $this->sliceSize;
+ }
+
+ /**
+ * @return int
+ */
+ public function getSliceNumber()
+ {
+ return $this->sliceNumber;
+ }
+}
diff --git a/src/ResultModifier/AsArray.php b/src/ResultModifier/AsArray.php
new file mode 100644
index 00000000..74af47f7
--- /dev/null
+++ b/src/ResultModifier/AsArray.php
@@ -0,0 +1,14 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\ResultModifier;
+
+class AsArray implements ResultModifier
+{
+}
diff --git a/src/ResultModifier/AsSingleScalar.php b/src/ResultModifier/AsSingleScalar.php
new file mode 100644
index 00000000..a6e47cee
--- /dev/null
+++ b/src/ResultModifier/AsSingleScalar.php
@@ -0,0 +1,14 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\ResultModifier;
+
+class AsSingleScalar implements ResultModifier
+{
+}
diff --git a/src/Result/Cache.php b/src/ResultModifier/Cache.php
similarity index 53%
rename from src/Result/Cache.php
rename to src/ResultModifier/Cache.php
index a4b39475..be66d38f 100644
--- a/src/Result/Cache.php
+++ b/src/ResultModifier/Cache.php
@@ -1,8 +1,13 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
-namespace Happyr\DoctrineSpecification\Result;
-
-use Doctrine\ORM\AbstractQuery;
+namespace Happyr\DoctrineSpecification\ResultModifier;
class Cache implements ResultModifier
{
@@ -20,10 +25,10 @@ public function __construct($cacheLifetime)
}
/**
- * @param AbstractQuery $query
+ * @return int
*/
- public function modify(AbstractQuery $query)
+ public function getCacheLifetime()
{
- $query->setResultCacheLifetime($this->cacheLifetime);
+ return $this->cacheLifetime;
}
}
diff --git a/src/ResultModifier/ResultModifier.php b/src/ResultModifier/ResultModifier.php
new file mode 100644
index 00000000..c52d7147
--- /dev/null
+++ b/src/ResultModifier/ResultModifier.php
@@ -0,0 +1,14 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\ResultModifier;
+
+interface ResultModifier
+{
+}
diff --git a/src/ResultModifier/ResultModifierCollection.php b/src/ResultModifier/ResultModifierCollection.php
new file mode 100644
index 00000000..3028aaaa
--- /dev/null
+++ b/src/ResultModifier/ResultModifierCollection.php
@@ -0,0 +1,47 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\ResultModifier;
+
+class ResultModifierCollection implements ResultModifier
+{
+ /**
+ * @var ResultModifier[]
+ */
+ private $modifiers = [];
+
+ /**
+ * Construct it with two or more instances of ResultModifier.
+ *
+ * @param ResultModifier $modifier1
+ * @param ResultModifier $modifier2
+ */
+ public function __construct(ResultModifier $modifier1, ResultModifier $modifier2)
+ {
+ foreach (func_get_args() as $modifier) {
+ $this->addModifier($modifier);
+ }
+ }
+
+ /**
+ * @param ResultModifier $modifier
+ */
+ public function addModifier(ResultModifier $modifier)
+ {
+ $this->modifiers[] = $modifier;
+ }
+
+ /**
+ * @return ResultModifier[]
+ */
+ public function getModifiers()
+ {
+ return $this->modifiers;
+ }
+}
diff --git a/src/ResultModifier/RoundDateTime.php b/src/ResultModifier/RoundDateTime.php
new file mode 100644
index 00000000..ed662adf
--- /dev/null
+++ b/src/ResultModifier/RoundDateTime.php
@@ -0,0 +1,37 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\ResultModifier;
+
+/**
+ * Round a \DateTime to enable caching.
+ */
+class RoundDateTime implements ResultModifier
+{
+ /**
+ * @var int How may seconds to round time
+ */
+ private $roundSeconds;
+
+ /**
+ * @param int $roundSeconds How may seconds to round time
+ */
+ public function __construct($roundSeconds)
+ {
+ $this->roundSeconds = $roundSeconds;
+ }
+
+ /**
+ * @return int
+ */
+ public function getRoundSeconds()
+ {
+ return $this->roundSeconds;
+ }
+}
diff --git a/src/Spec.php b/src/Spec.php
deleted file mode 100644
index d430da9b..00000000
--- a/src/Spec.php
+++ /dev/null
@@ -1,377 +0,0 @@
-newInstanceArgs($args);
- }
-
- /**
- * @return OrX
- */
- public static function orX()
- {
- $args = func_get_args();
- $reflection = new \ReflectionClass('Happyr\DoctrineSpecification\Logic\OrX');
-
- return $reflection->newInstanceArgs($args);
- }
-
- /**
- * @param Filter $spec
- *
- * @return Not
- */
- public static function not(Filter $spec)
- {
- return new Not($spec);
- }
-
- /*
- * Query modifier
- */
-
- /**
- * @param string $field
- * @param string $newAlias
- * @param string $dqlAlias
- *
- * @return Join
- */
- public static function join($field, $newAlias, $dqlAlias = null)
- {
- return new Join($field, $newAlias, $dqlAlias);
- }
-
- /**
- * @param string $field
- * @param string $newAlias
- * @param string $dqlAlias
- *
- * @return LeftJoin
- */
- public static function leftJoin($field, $newAlias, $dqlAlias = null)
- {
- return new LeftJoin($field, $newAlias, $dqlAlias);
- }
-
- /**
- * @param string $field
- * @param string $newAlias
- * @param string $dqlAlias
- *
- * @return InnerJoin
- */
- public static function innerJoin($field, $newAlias, $dqlAlias = null)
- {
- return new InnerJoin($field, $newAlias, $dqlAlias);
- }
-
- /**
- * @param int $count
- *
- * @return Limit
- */
- public static function limit($count)
- {
- return new Limit($count);
- }
-
- /**
- * @param int $count
- *
- * @return Offset
- */
- public static function offset($count)
- {
- return new Offset($count);
- }
-
- /**
- * @param int $sliceSize
- * @param int $sliceNumber
- *
- * @return Slice
- */
- public static function slice($sliceSize, $sliceNumber = 0)
- {
- return new Slice($sliceSize, $sliceNumber);
- }
-
- /**
- * @param string $field
- * @param string $order
- * @param string|null $dqlAlias
- *
- * @return OrderBy
- */
- public static function orderBy($field, $order = 'ASC', $dqlAlias = null)
- {
- return new OrderBy($field, $order, $dqlAlias);
- }
-
- /**
- * @param string $field
- * @param string $dqlAlias
- *
- * @return GroupBy
- */
- public static function groupBy($field, $dqlAlias = null)
- {
- return new GroupBy($field, $dqlAlias);
- }
-
- /*
- * Result modifier
- */
-
- /**
- * @return AsArray
- */
- public static function asArray()
- {
- return new AsArray();
- }
-
- /**
- * @return AsSingleScalar
- */
- public static function asSingleScalar()
- {
- return new AsSingleScalar();
- }
-
- /**
- * @param int $cacheLifetime How many seconds the cached entry is valid
- *
- * @return Cache
- */
- public static function cache($cacheLifetime)
- {
- return new Cache($cacheLifetime);
- }
-
- /**
- * @param int $roundSeconds How may seconds to round time
- *
- * @return RoundDateTime
- */
- public static function roundDateTimeParams($roundSeconds)
- {
- return new RoundDateTime($roundSeconds);
- }
-
- /*
- * Filters
- */
-
- /**
- * @param string $field
- * @param string|null $dqlAlias
- *
- * @return IsNull
- */
- public static function isNull($field, $dqlAlias = null)
- {
- return new IsNull($field, $dqlAlias);
- }
-
- /**
- * @param string $field
- * @param string|null $dqlAlias
- *
- * @return IsNotNull
- */
- public static function isNotNull($field, $dqlAlias = null)
- {
- return new IsNotNull($field, $dqlAlias);
- }
-
- /**
- * Make sure the $field has a value equals to $value.
- *
- * @param string $field
- * @param mixed $value
- * @param string $dqlAlias
- *
- * @return In
- */
- public static function in($field, $value, $dqlAlias = null)
- {
- return new In($field, $value, $dqlAlias);
- }
-
- /**
- * @param string $field
- * @param mixed $value
- * @param string $dqlAlias
- *
- * @return Not
- */
- public static function notIn($field, $value, $dqlAlias = null)
- {
- return new Not(new In($field, $value, $dqlAlias));
- }
-
- /**
- * @param string $field
- * @param string $value
- * @param string $dqlAlias
- *
- * @return Comparison
- */
- public static function eq($field, $value, $dqlAlias = null)
- {
- return new Comparison(Comparison::EQ, $field, $value, $dqlAlias);
- }
-
- /**
- * @param string $field
- * @param string $value
- * @param string $dqlAlias
- *
- * @return Comparison
- */
- public static function neq($field, $value, $dqlAlias = null)
- {
- return new Comparison(Comparison::NEQ, $field, $value, $dqlAlias);
- }
-
- /**
- * @param string $field
- * @param string $value
- * @param string $dqlAlias
- *
- * @return Comparison
- */
- public static function lt($field, $value, $dqlAlias = null)
- {
- return new Comparison(Comparison::LT, $field, $value, $dqlAlias);
- }
-
- /**
- * @param string $field
- * @param string $value
- * @param string $dqlAlias
- *
- * @return Comparison
- */
- public static function lte($field, $value, $dqlAlias = null)
- {
- return new Comparison(Comparison::LTE, $field, $value, $dqlAlias);
- }
-
- /**
- * @param string $field
- * @param string $value
- * @param string $dqlAlias
- *
- * @return Comparison
- */
- public static function gt($field, $value, $dqlAlias = null)
- {
- return new Comparison(Comparison::GT, $field, $value, $dqlAlias);
- }
-
- /**
- * @param string $field
- * @param string $value
- * @param string $dqlAlias
- *
- * @return Comparison
- */
- public static function gte($field, $value, $dqlAlias = null)
- {
- return new Comparison(Comparison::GTE, $field, $value, $dqlAlias);
- }
-
- /**
- * @param string $field
- * @param string $value
- * @param string $format
- * @param string $dqlAlias
- *
- * @return Like
- */
- public static function like($field, $value, $format = Like::CONTAINS, $dqlAlias = null)
- {
- return new Like($field, $value, $format, $dqlAlias);
- }
-
- /**
- * @param string $value
- * @param null $dqlAlias
- *
- * @return InstanceOfX
- */
- public static function instanceOfX($value, $dqlAlias = null)
- {
- return new InstanceOfX($value, $dqlAlias);
- }
-
- /*
- * Specifications
- */
-
- /**
- * @param Specification $spec
- *
- * @return CountOf
- */
- public static function countOf(Specification $spec)
- {
- return new CountOf($spec);
- }
-
- /**
- * @param Filter|string $spec
- *
- * @return Having
- */
- public static function having($spec)
- {
- return new Having($spec);
- }
-}
diff --git a/src/Specification.php b/src/Specification.php
new file mode 100644
index 00000000..7edeecee
--- /dev/null
+++ b/src/Specification.php
@@ -0,0 +1,14 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification;
+
+interface Specification
+{
+}
diff --git a/src/Specification/CountOf.php b/src/Specification/CountOf.php
deleted file mode 100644
index 1260d7a0..00000000
--- a/src/Specification/CountOf.php
+++ /dev/null
@@ -1,46 +0,0 @@
-child = $child;
- }
-
- /**
- * @param QueryBuilder $qb
- * @param string $dqlAlias
- *
- * @return string
- */
- public function getFilter(QueryBuilder $qb, $dqlAlias)
- {
- $qb->select(sprintf('COUNT(%s)', $dqlAlias));
-
- return $this->child->getFilter($qb, $dqlAlias);
- }
-
- /**
- * @param QueryBuilder $qb
- * @param string $dqlAlias
- */
- public function modify(QueryBuilder $qb, $dqlAlias)
- {
- $this->child->modify($qb, $dqlAlias);
- }
-}
diff --git a/src/Specification/Having.php b/src/Specification/Having.php
deleted file mode 100644
index 53853e79..00000000
--- a/src/Specification/Having.php
+++ /dev/null
@@ -1,49 +0,0 @@
-child = $child;
- }
-
- /**
- * @param QueryBuilder $qb
- * @param string $dqlAlias
- */
- public function modify(QueryBuilder $qb, $dqlAlias)
- {
- if ($this->child instanceof QueryModifier) {
- $this->child->modify($qb, $dqlAlias);
- }
- }
-
- /**
- * @param QueryBuilder $qb
- * @param string $dqlAlias
- *
- * @return string
- */
- public function getFilter(QueryBuilder $qb, $dqlAlias)
- {
- if ($this->child instanceof Filter) {
- $qb->having($this->child->getFilter($qb, $dqlAlias));
- } else {
- $qb->having($this->child);
- }
- }
-}
diff --git a/src/Specification/Specification.php b/src/Specification/Specification.php
deleted file mode 100644
index b051c2e2..00000000
--- a/src/Specification/Specification.php
+++ /dev/null
@@ -1,10 +0,0 @@
-
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification;
+
+class SpecificationCollection implements Specification
+{
+ /**
+ * @var Specification[]
+ */
+ private $specifications;
+
+ /**
+ * Construct it with two or more instances of Specification.
+ *
+ * @param Specification $specification1
+ * @param Specification $specification2
+ */
+ public function __construct(Specification $specification1, Specification $specification2)
+ {
+ foreach (func_get_args() as $specification) {
+ $this->addSpecification($specification);
+ }
+ }
+
+ /**
+ * @param Specification $specification
+ */
+ public function addSpecification(Specification $specification)
+ {
+ $this->specifications[] = $specification;
+ }
+
+ /**
+ * @return Specification[]
+ */
+ public function getSpecifications()
+ {
+ return $this->specifications;
+ }
+}
diff --git a/src/DBALTypesResolver.php b/src/Transformer/Doctrine/DBALTypesResolver.php
similarity index 84%
rename from src/DBALTypesResolver.php
rename to src/Transformer/Doctrine/DBALTypesResolver.php
index 3eb18503..c3685645 100644
--- a/src/DBALTypesResolver.php
+++ b/src/Transformer/Doctrine/DBALTypesResolver.php
@@ -1,6 +1,13 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
-namespace Happyr\DoctrineSpecification;
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine;
use Doctrine\DBAL\Types\Type;
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/DoctrineODMMongoDBTransformer.php b/src/Transformer/Doctrine/ODM/MongoDB/DoctrineODMMongoDBTransformer.php
new file mode 100644
index 00000000..414f2e0f
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/DoctrineODMMongoDBTransformer.php
@@ -0,0 +1,44 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB;
+
+use Doctrine\MongoDB\Query\Query;
+use Doctrine\ODM\MongoDB\Query\Builder;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\QueryBuilderTransformerCollection;
+
+class DoctrineODMMongoDBTransformer
+{
+ /**
+ * @var QueryBuilderTransformerCollection
+ */
+ private $transformer;
+
+ /**
+ * @param QueryBuilderTransformerCollection $transformer
+ */
+ public function __construct(QueryBuilderTransformerCollection $transformer)
+ {
+ $this->transformer = $transformer;
+ }
+
+ /**
+ * @param Specification $specification
+ * @param Builder $qb
+ *
+ * @return Query
+ */
+ public function transform(Specification $specification, Builder $qb)
+ {
+ $this->transformer->transform($specification, $qb);
+
+ return $qb->getQuery();
+ }
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/EntitySpecificationRepository.php b/src/Transformer/Doctrine/ODM/MongoDB/EntitySpecificationRepository.php
new file mode 100644
index 00000000..3a28cbd1
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/EntitySpecificationRepository.php
@@ -0,0 +1,41 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB;
+
+use Doctrine\ODM\MongoDB\DocumentManager;
+use Doctrine\ODM\MongoDB\UnitOfWork;
+use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
+use Doctrine\ODM\MongoDB\DocumentRepository;
+use Doctrine\Common\Collections\Selectable;
+use Doctrine\Common\Persistence\ObjectRepository;
+
+/**
+ * This class allows you to use a Specification to query entities.
+ */
+class EntitySpecificationRepository extends DocumentRepository implements EntitySpecificationRepositoryInterface, ObjectRepository, Selectable
+{
+ use EntitySpecificationRepositoryTrait;
+
+ /**
+ * @param DocumentManager $dm the DocumentManager to use
+ * @param UnitOfWork $uow the UnitOfWork to use
+ * @param ClassMetadata $class the class descriptor
+ * @param DoctrineODMMongoDBTransformer $transformer The Specification transformer
+ */
+ public function __construct(
+ DocumentManager $dm,
+ UnitOfWork $uow,
+ ClassMetadata $class,
+ DoctrineODMMongoDBTransformer $transformer
+ ) {
+ parent::__construct($dm, $uow, $class);
+ $this->setTransformer($transformer);
+ }
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/EntitySpecificationRepositoryInterface.php b/src/Transformer/Doctrine/ODM/MongoDB/EntitySpecificationRepositoryInterface.php
new file mode 100644
index 00000000..ae001122
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/EntitySpecificationRepositoryInterface.php
@@ -0,0 +1,53 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB;
+
+use Doctrine\ODM\MongoDB\Query\Builder;
+use Happyr\DoctrineSpecification\Specification;
+
+/**
+ * This interface should be used by an DocumentRepository implementing the Specification pattern.
+ */
+interface EntitySpecificationRepositoryInterface
+{
+ /**
+ * Get results when you match with a Specification.
+ *
+ * @param Specification $specification
+ *
+ * @return mixed[]
+ */
+ public function match(Specification $specification);
+
+ /**
+ * Get single result when you match with a Specification.
+ *
+ * @param Specification $specification
+ *
+ * @return mixed
+ */
+ public function matchSingleResult(Specification $specification);
+
+ /**
+ * Prepare a Query with a Specification.
+ *
+ * @param Specification $specification
+ *
+ * @return Builder
+ */
+ public function getQuery(Specification $specification);
+
+ /**
+ * @param DoctrineODMMongoDBTransformer $transformer
+ *
+ * @return self
+ */
+ public function setTransformer(DoctrineODMMongoDBTransformer $transformer);
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/EntitySpecificationRepositoryTrait.php b/src/Transformer/Doctrine/ODM/MongoDB/EntitySpecificationRepositoryTrait.php
new file mode 100644
index 00000000..5c3a4edd
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/EntitySpecificationRepositoryTrait.php
@@ -0,0 +1,81 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB;
+
+use Doctrine\ODM\MongoDB\Query\Builder;
+use Doctrine\ODM\MongoDB\Query\Query;
+use Happyr\DoctrineSpecification\Specification;
+
+/**
+ * This trait should be used by a class extending \Doctrine\ODM\MongoDB\DocumentRepository.
+ */
+trait EntitySpecificationRepositoryTrait
+{
+ /**
+ * @var DoctrineODMMongoDBTransformer
+ */
+ private $transformer;
+
+ /**
+ * Get results when you match with a Specification.
+ *
+ * @param Specification $specification
+ *
+ * @return mixed[]
+ */
+ public function match(Specification $specification)
+ {
+ return $this->getQuery($specification)->execute();
+ }
+
+ /**
+ * Get single result when you match with a Specification.
+ *
+ * @param Specification $specification
+ *
+ * @return mixed
+ */
+ public function matchSingleResult(Specification $specification)
+ {
+ return $this->getQuery($specification)->getSingleResult();
+ }
+
+ /**
+ * Prepare a Query with a Specification.
+ *
+ * @param Specification $specification
+ *
+ * @return Query
+ */
+ public function getQuery(Specification $specification)
+ {
+ /* @var $qb Builder */
+ $qb = $this->createQueryBuilder();
+
+ // apply specification
+ if ($this->transformer instanceof DoctrineODMMongoDBTransformer) {
+ return $this->transformer->transform($specification, $qb);
+ } else {
+ return $qb->getQuery();
+ }
+ }
+
+ /**
+ * @param DoctrineODMMongoDBTransformer $transformer
+ *
+ * @return self
+ */
+ public function setTransformer(DoctrineODMMongoDBTransformer $transformer)
+ {
+ $this->transformer = $transformer;
+
+ return $this;
+ }
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/EqualsTransformer.php b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/EqualsTransformer.php
new file mode 100644
index 00000000..eb914a18
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/EqualsTransformer.php
@@ -0,0 +1,29 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\Filter;
+
+use Doctrine\ODM\MongoDB\Query\Builder;
+use Happyr\DoctrineSpecification\Filter\Equals;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\QueryBuilderTransformer;
+
+class EqualsTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param Builder $qb
+ */
+ public function transform(Specification $specification, Builder $qb)
+ {
+ if ($specification instanceof Equals) {
+ $qb->field($specification->getField())->equals($specification->getValue());
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/GreaterOrEqualThanTransformer.php b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/GreaterOrEqualThanTransformer.php
new file mode 100644
index 00000000..a060655b
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/GreaterOrEqualThanTransformer.php
@@ -0,0 +1,29 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\Filter;
+
+use Doctrine\ODM\MongoDB\Query\Builder;
+use Happyr\DoctrineSpecification\Filter\GreaterOrEqualThan;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\QueryBuilderTransformer;
+
+class GreaterOrEqualThanTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param Builder $qb
+ */
+ public function transform(Specification $specification, Builder $qb)
+ {
+ if ($specification instanceof GreaterOrEqualThan) {
+ $qb->field($specification->getField())->gte($specification->getValue());
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/GreaterThanTransformer.php b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/GreaterThanTransformer.php
new file mode 100644
index 00000000..116d7570
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/GreaterThanTransformer.php
@@ -0,0 +1,29 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\Filter;
+
+use Doctrine\ODM\MongoDB\Query\Builder;
+use Happyr\DoctrineSpecification\Filter\GreaterThan;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\QueryBuilderTransformer;
+
+class GreaterThanTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param Builder $qb
+ */
+ public function transform(Specification $specification, Builder $qb)
+ {
+ if ($specification instanceof GreaterThan) {
+ $qb->field($specification->getField())->gt($specification->getValue());
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/InTransformer.php b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/InTransformer.php
new file mode 100644
index 00000000..f0eefd3e
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/InTransformer.php
@@ -0,0 +1,29 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\Filter;
+
+use Doctrine\ODM\MongoDB\Query\Builder;
+use Happyr\DoctrineSpecification\Filter\In;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\QueryBuilderTransformer;
+
+class InTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param Builder $qb
+ */
+ public function transform(Specification $specification, Builder $qb)
+ {
+ if ($specification instanceof In) {
+ $qb->field($specification->getField())->equals($specification->getValue());
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/LessOrEqualThanTransformer.php b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/LessOrEqualThanTransformer.php
new file mode 100644
index 00000000..6fda4b89
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/LessOrEqualThanTransformer.php
@@ -0,0 +1,29 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\Filter;
+
+use Doctrine\ODM\MongoDB\Query\Builder;
+use Happyr\DoctrineSpecification\Filter\LessOrEqualThan;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\QueryBuilderTransformer;
+
+class LessOrEqualThanTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param Builder $qb
+ */
+ public function transform(Specification $specification, Builder $qb)
+ {
+ if ($specification instanceof LessOrEqualThan) {
+ $qb->field($specification->getField())->lte($specification->getValue());
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/LessThanTransformer.php b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/LessThanTransformer.php
new file mode 100644
index 00000000..5e713719
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/LessThanTransformer.php
@@ -0,0 +1,29 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\Filter;
+
+use Doctrine\ODM\MongoDB\Query\Builder;
+use Happyr\DoctrineSpecification\Filter\LessThan;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\QueryBuilderTransformer;
+
+class LessThanTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param Builder $qb
+ */
+ public function transform(Specification $specification, Builder $qb)
+ {
+ if ($specification instanceof LessThan) {
+ $qb->field($specification->getField())->lt($specification->getValue());
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/Logic/AndXTransformer.php b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/Logic/AndXTransformer.php
new file mode 100644
index 00000000..6cb4efe1
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/Logic/AndXTransformer.php
@@ -0,0 +1,34 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\Filter\Logic;
+
+use Doctrine\ODM\MongoDB\Query\Builder;
+use Happyr\DoctrineSpecification\Filter\Logic\AndX;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\QueryBuilderTransformerCollectionAware;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\QueryBuilderTransformerCollectionAwareTrait;
+
+class AndXTransformer implements QueryBuilderTransformerCollectionAware
+{
+ use QueryBuilderTransformerCollectionAwareTrait;
+
+ /**
+ * @param Specification $specification
+ * @param Builder $qb
+ */
+ public function transform(Specification $specification, Builder $qb)
+ {
+ if ($specification instanceof AndX) {
+ foreach ($specification->getFilters() as $filter) {
+ $this->collection->transform($filter, $qb);
+ }
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/NotEqualsTransformer.php b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/NotEqualsTransformer.php
new file mode 100644
index 00000000..a0c85864
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/Filter/NotEqualsTransformer.php
@@ -0,0 +1,29 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\Filter;
+
+use Doctrine\ODM\MongoDB\Query\Builder;
+use Happyr\DoctrineSpecification\Filter\NotEquals;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\QueryBuilderTransformer;
+
+class NotEqualsTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param Builder $qb
+ */
+ public function transform(Specification $specification, Builder $qb)
+ {
+ if ($specification instanceof NotEquals) {
+ $qb->field($specification->getField())->notEqual($specification->getValue());
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/QueryBuilderTransformer.php b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/QueryBuilderTransformer.php
new file mode 100644
index 00000000..f5d08877
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/QueryBuilderTransformer.php
@@ -0,0 +1,22 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder;
+
+use Doctrine\ODM\MongoDB\Query\Builder;
+use Happyr\DoctrineSpecification\Specification;
+
+interface QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param Builder $qb
+ */
+ public function transform(Specification $specification, Builder $qb);
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/QueryBuilderTransformerCollection.php b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/QueryBuilderTransformerCollection.php
new file mode 100644
index 00000000..3c540293
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/QueryBuilderTransformerCollection.php
@@ -0,0 +1,54 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder;
+
+use Doctrine\ODM\MongoDB\Query\Builder;
+use Happyr\DoctrineSpecification\Specification;
+
+class QueryBuilderTransformerCollection implements QueryBuilderTransformer
+{
+ /**
+ * @var QueryBuilderTransformer[]
+ */
+ private $transformers = [];
+
+ /**
+ * @param QueryBuilderTransformer[] $transformers
+ */
+ public function __construct(array $transformers = [])
+ {
+ foreach ($transformers as $transformer) {
+ $this->addTransformer($transformer);
+ }
+ }
+
+ /**
+ * @param QueryBuilderTransformer $transformer
+ */
+ public function addTransformer(QueryBuilderTransformer $transformer)
+ {
+ $this->transformers[] = $transformer;
+
+ if ($transformer instanceof QueryBuilderTransformerCollectionAware) {
+ $transformer->setCollection($this);
+ }
+ }
+
+ /**
+ * @param Specification $specification
+ * @param Builder $qb
+ */
+ public function transform(Specification $specification, Builder $qb)
+ {
+ foreach ($this->transformers as $transformer) {
+ $transformer->transform($specification, $qb);
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/QueryBuilderTransformerCollectionAware.php b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/QueryBuilderTransformerCollectionAware.php
new file mode 100644
index 00000000..d5227f35
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/QueryBuilderTransformerCollectionAware.php
@@ -0,0 +1,18 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder;
+
+interface QueryBuilderTransformerCollectionAware extends QueryBuilderTransformer
+{
+ /**
+ * @param QueryBuilderTransformerCollection $collection
+ */
+ public function setCollection(QueryBuilderTransformerCollection $collection);
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/QueryBuilderTransformerCollectionAwareTrait.php b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/QueryBuilderTransformerCollectionAwareTrait.php
new file mode 100644
index 00000000..22e17e60
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/QueryBuilderTransformerCollectionAwareTrait.php
@@ -0,0 +1,26 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder;
+
+trait QueryBuilderTransformerCollectionAwareTrait
+{
+ /**
+ * @var QueryBuilderTransformerCollection
+ */
+ protected $collection;
+
+ /**
+ * @param QueryBuilderTransformerCollection $collection
+ */
+ public function setCollection(QueryBuilderTransformerCollection $collection)
+ {
+ $this->collection = $collection;
+ }
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/QueryModifier/MapTransformer.php b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/QueryModifier/MapTransformer.php
new file mode 100644
index 00000000..2031d732
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/QueryModifier/MapTransformer.php
@@ -0,0 +1,29 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\QueryModifier;
+
+use Doctrine\ODM\MongoDB\Query\Builder;
+use Happyr\DoctrineSpecification\QueryModifier\Map;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\QueryBuilderTransformer;
+
+class MapTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param Builder $qb
+ */
+ public function transform(Specification $specification, Builder $qb)
+ {
+ if ($specification instanceof Map) {
+ $qb->map($specification->getMap());
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/QueryModifier/ReduceTransformer.php b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/QueryModifier/ReduceTransformer.php
new file mode 100644
index 00000000..0e462e11
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/QueryModifier/ReduceTransformer.php
@@ -0,0 +1,29 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\QueryModifier;
+
+use Doctrine\ODM\MongoDB\Query\Builder;
+use Happyr\DoctrineSpecification\QueryModifier\Reduce;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\QueryBuilderTransformer;
+
+class ReduceTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param Builder $qb
+ */
+ public function transform(Specification $specification, Builder $qb)
+ {
+ if ($specification instanceof Reduce) {
+ $qb->reduce($specification->getReduce());
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/ResultManagement/CountOfTransformer.php b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/ResultManagement/CountOfTransformer.php
new file mode 100644
index 00000000..58b50dfa
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/ResultManagement/CountOfTransformer.php
@@ -0,0 +1,29 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\ResultManagement;
+
+use Doctrine\ODM\MongoDB\Query\Builder;
+use Happyr\DoctrineSpecification\ResultManagement\CountOf;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\QueryBuilderTransformer;
+
+class CountOfTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param Builder $qb
+ */
+ public function transform(Specification $specification, Builder $qb)
+ {
+ if ($specification instanceof CountOf) {
+ $qb->count();
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/ResultManagement/LimitTransformer.php b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/ResultManagement/LimitTransformer.php
new file mode 100644
index 00000000..b27b131d
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/ResultManagement/LimitTransformer.php
@@ -0,0 +1,29 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\ResultManagement;
+
+use Doctrine\ODM\MongoDB\Query\Builder;
+use Happyr\DoctrineSpecification\ResultManagement\Limit;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\QueryBuilderTransformer;
+
+class LimitTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param Builder $qb
+ */
+ public function transform(Specification $specification, Builder $qb)
+ {
+ if ($specification instanceof Limit) {
+ $qb->limit($specification->getLimit());
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/ResultManagement/OffsetTransformer.php b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/ResultManagement/OffsetTransformer.php
new file mode 100644
index 00000000..de703a6a
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/ResultManagement/OffsetTransformer.php
@@ -0,0 +1,29 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\ResultManagement;
+
+use Doctrine\ODM\MongoDB\Query\Builder;
+use Happyr\DoctrineSpecification\ResultManagement\Offset;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\QueryBuilderTransformer;
+
+class OffsetTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param Builder $qb
+ */
+ public function transform(Specification $specification, Builder $qb)
+ {
+ if ($specification instanceof Offset) {
+ $qb->skip($specification->getOffset());
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/ResultManagement/OrderByTransformer.php b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/ResultManagement/OrderByTransformer.php
new file mode 100644
index 00000000..1d1d565f
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/ResultManagement/OrderByTransformer.php
@@ -0,0 +1,29 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\ResultManagement;
+
+use Doctrine\ODM\MongoDB\Query\Builder;
+use Happyr\DoctrineSpecification\ResultManagement\OrderBy;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\QueryBuilderTransformer;
+
+class OrderByTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param Builder $qb
+ */
+ public function transform(Specification $specification, Builder $qb)
+ {
+ if ($specification instanceof OrderBy) {
+ $qb->sort($specification->getField(), $specification->getOrder());
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/ResultManagement/SliceTransformer.php b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/ResultManagement/SliceTransformer.php
new file mode 100644
index 00000000..8213c43a
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/ResultManagement/SliceTransformer.php
@@ -0,0 +1,33 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\ResultManagement;
+
+use Doctrine\ODM\MongoDB\Query\Builder;
+use Happyr\DoctrineSpecification\ResultManagement\Slice;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder\QueryBuilderTransformer;
+
+class SliceTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param Builder $qb
+ */
+ public function transform(Specification $specification, Builder $qb)
+ {
+ if ($specification instanceof Slice) {
+ $qb->limit($specification->getSliceSize());
+
+ if ($specification->getSliceNumber() > 0) {
+ $qb->skip($specification->getSliceNumber() * $specification->getSliceSize());
+ }
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/SpecificationCollectionTransformer.php b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/SpecificationCollectionTransformer.php
new file mode 100644
index 00000000..5de3f2d0
--- /dev/null
+++ b/src/Transformer/Doctrine/ODM/MongoDB/QueryBuilder/SpecificationCollectionTransformer.php
@@ -0,0 +1,32 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ODM\MongoDB\QueryBuilder;
+
+use Doctrine\ODM\MongoDB\Query\Builder;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\SpecificationCollection;
+
+class SpecificationCollectionTransformer implements QueryBuilderTransformerCollectionAware
+{
+ use QueryBuilderTransformerCollectionAwareTrait;
+
+ /**
+ * @param Specification $specification
+ * @param Builder $qb
+ */
+ public function transform(Specification $specification, Builder $qb)
+ {
+ if ($specification instanceof SpecificationCollection) {
+ foreach ($specification->getSpecifications() as $specification) {
+ $this->collection->transform($specification, $qb);
+ }
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/DoctrineORMTransformer.php b/src/Transformer/Doctrine/ORM/DoctrineORMTransformer.php
new file mode 100644
index 00000000..cfa4798e
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/DoctrineORMTransformer.php
@@ -0,0 +1,71 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM;
+
+use Doctrine\ORM\AbstractQuery;
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\ResultModifier\ResultModifier;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Query\QueryTransformerCollection;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformerCollection;
+
+class DoctrineORMTransformer
+{
+ /**
+ * @var QueryTransformerCollection
+ */
+ private $qTransformer;
+
+ /**
+ * @var QueryBuilderTransformerCollection
+ */
+ private $qbTransformer;
+
+ /**
+ * @param QueryTransformerCollection $qTransformer
+ * @param QueryBuilderTransformerCollection $qbTransformer
+ */
+ public function __construct(
+ QueryTransformerCollection $qTransformer,
+ QueryBuilderTransformerCollection $qbTransformer
+ ) {
+ $this->qTransformer = $qTransformer;
+ $this->qbTransformer = $qbTransformer;
+ }
+
+ /**
+ * @param Specification $specification
+ * @param ResultModifier|null $modifier
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return AbstractQuery
+ */
+ public function transform(
+ Specification $specification,
+ ResultModifier $modifier = null,
+ QueryBuilder $qb,
+ $dqlAlias
+ ) {
+ $condition = $this->qbTransformer->transform($specification, $qb, $dqlAlias);
+
+ if ($condition) {
+ $qb->andWhere($condition);
+ }
+
+ $query = $qb->getQuery();
+
+ if ($modifier !== null) {
+ $this->qTransformer->transform($modifier, $query);
+ }
+
+ return $query;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/EntitySpecificationRepository.php b/src/Transformer/Doctrine/ORM/EntitySpecificationRepository.php
new file mode 100644
index 00000000..e5867ee7
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/EntitySpecificationRepository.php
@@ -0,0 +1,35 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM;
+
+use Doctrine\ORM\EntityManager;
+use Doctrine\ORM\EntityRepository;
+use Doctrine\Common\Collections\Selectable;
+use Doctrine\Common\Persistence\ObjectRepository;
+use Doctrine\ORM\Mapping\ClassMetadata;
+
+/**
+ * This class allows you to use a Specification to query entities.
+ */
+class EntitySpecificationRepository extends EntityRepository implements EntitySpecificationRepositoryInterface, ObjectRepository, Selectable
+{
+ use EntitySpecificationRepositoryTrait;
+
+ /**
+ * @param EntityManager $em The EntityManager to use
+ * @param ClassMetadata $class The class descriptor
+ * @param DoctrineORMTransformer $transformer The Specification transformer
+ */
+ public function __construct($em, ClassMetadata $class, DoctrineORMTransformer $transformer)
+ {
+ parent::__construct($em, $class);
+ $this->setTransformer($transformer);
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/EntitySpecificationRepositoryInterface.php b/src/Transformer/Doctrine/ORM/EntitySpecificationRepositoryInterface.php
new file mode 100644
index 00000000..5a1f8406
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/EntitySpecificationRepositoryInterface.php
@@ -0,0 +1,79 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM;
+
+use Doctrine\ORM\Query;
+use Happyr\DoctrineSpecification\ResultModifier\ResultModifier;
+use Happyr\DoctrineSpecification\Specification;
+
+/**
+ * This interface should be used by an EntityRepository implementing the Specification pattern.
+ */
+interface EntitySpecificationRepositoryInterface
+{
+ /**
+ * Get results when you match with a Specification.
+ *
+ * @param Specification $specification
+ * @param ResultModifier $modifier
+ *
+ * @return mixed[]
+ */
+ public function match(Specification $specification, ResultModifier $modifier);
+
+ /**
+ * Get single result when you match with a Specification.
+ *
+ * @param Specification $specification
+ * @param ResultModifier $modifier
+ *
+ * @throw NonUniqueException If more than one result is found
+ * @throw NoResultException If no results found
+ *
+ * @return mixed
+ */
+ public function matchSingleResult(Specification $specification, ResultModifier $modifier);
+
+ /**
+ * Get single result or null when you match with a Specification.
+ *
+ * @param Specification $specification
+ * @param ResultModifier $modifier
+ *
+ * @throw NonUniqueException If more than one result is found
+ *
+ * @return mixed|null
+ */
+ public function matchOneOrNullResult(Specification $specification, ResultModifier $modifier);
+
+ /**
+ * Prepare a Query with a Specification.
+ *
+ * @param Specification $specification
+ * @param ResultModifier $modifier
+ *
+ * @return Query
+ */
+ public function getQuery(Specification $specification, ResultModifier $modifier);
+
+ /**
+ * @param string $alias
+ *
+ * @return self
+ */
+ public function setAlias($alias);
+
+ /**
+ * @param DoctrineORMTransformer $transformer
+ *
+ * @return self
+ */
+ public function setTransformer(DoctrineORMTransformer $transformer);
+}
diff --git a/src/Transformer/Doctrine/ORM/EntitySpecificationRepositoryTrait.php b/src/Transformer/Doctrine/ORM/EntitySpecificationRepositoryTrait.php
new file mode 100644
index 00000000..d05a42cf
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/EntitySpecificationRepositoryTrait.php
@@ -0,0 +1,134 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM;
+
+use Doctrine\ORM\NonUniqueResultException;
+use Doctrine\ORM\NoResultException;
+use Doctrine\ORM\Query;
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\Exception\NonUniqueResultException as HappyrNonUniqueResultException;
+use Happyr\DoctrineSpecification\Exception\NoResultException as HappyrNoResultException;
+use Happyr\DoctrineSpecification\ResultModifier\ResultModifier;
+use Happyr\DoctrineSpecification\Specification;
+
+/**
+ * This trait should be used by a class extending \Doctrine\ORM\EntityRepository.
+ */
+trait EntitySpecificationRepositoryTrait
+{
+ /**
+ * @var string alias
+ */
+ private $alias = 'e';
+
+ /**
+ * @var DoctrineORMTransformer
+ */
+ private $transformer;
+
+ /**
+ * Get results when you match with a Specification.
+ *
+ * @param Specification $specification
+ * @param ResultModifier $modifier
+ *
+ * @return mixed[]
+ */
+ public function match(Specification $specification, ResultModifier $modifier = null)
+ {
+ return $this->getQuery($specification, $modifier)->execute();
+ }
+
+ /**
+ * Get single result when you match with a Specification.
+ *
+ * @param Specification $specification
+ * @param ResultModifier $modifier
+ *
+ * @throw HappyrNonUniqueResultException If more than one result is found
+ * @throw HappyrNoResultException If no results found
+ *
+ * @return mixed
+ */
+ public function matchSingleResult(Specification $specification, ResultModifier $modifier = null)
+ {
+ try {
+ return $this->getQuery($specification, $modifier)->getSingleResult();
+ } catch (NonUniqueResultException $e) {
+ throw new HappyrNonUniqueResultException($e->getMessage(), $e->getCode(), $e);
+ } catch (NoResultException $e) {
+ throw new HappyrNoResultException($e->getMessage(), $e->getCode(), $e);
+ }
+ }
+
+ /**
+ * Get single result or null when you match with a Specification.
+ *
+ * @param Specification $specification
+ * @param ResultModifier $modifier
+ *
+ * @throw HappyrNonUniqueResultException If more than one result is found
+ *
+ * @return mixed|null
+ */
+ public function matchOneOrNullResult(Specification $specification, ResultModifier $modifier = null)
+ {
+ try {
+ return $this->matchSingleResult($specification, $modifier);
+ } catch (HappyrNoResultException $e) {
+ return null;
+ }
+ }
+
+ /**
+ * Prepare a Query with a Specification.
+ *
+ * @param Specification $specification
+ * @param ResultModifier $modifier
+ *
+ * @return Query
+ */
+ public function getQuery(Specification $specification, ResultModifier $modifier = null)
+ {
+ /* @var $qb QueryBuilder */
+ $qb = $this->createQueryBuilder($this->alias);
+
+ // apply specification
+ if ($this->transformer instanceof DoctrineORMTransformer) {
+ return $this->transformer->transform($specification, $modifier, $qb, $this->alias);
+ } else {
+ return $qb->getQuery();
+ }
+ }
+
+ /**
+ * @param string $alias
+ *
+ * @return self
+ */
+ public function setAlias($alias)
+ {
+ $this->alias = $alias;
+
+ return $this;
+ }
+
+ /**
+ * @param DoctrineORMTransformer $transformer
+ *
+ * @return self
+ */
+ public function setTransformer(DoctrineORMTransformer $transformer)
+ {
+ $this->transformer = $transformer;
+
+ return $this;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/Exception/InvalidArgumentException.php b/src/Transformer/Doctrine/ORM/Exception/InvalidArgumentException.php
new file mode 100644
index 00000000..a5127800
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/Exception/InvalidArgumentException.php
@@ -0,0 +1,30 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Exception;
+
+use Happyr\DoctrineSpecification\Exception\InvalidArgumentException as BaseInvalidArgumentException;
+
+class InvalidArgumentException extends BaseInvalidArgumentException
+{
+ /**
+ * @param array $supported_operators
+ * @param string $operator
+ *
+ * @return self
+ */
+ public static function invalidComparisonOperator(array $supported_operators, $operator)
+ {
+ return new self(sprintf(
+ '"%s" is not a valid comparison operator. Valid operators are: "%s"',
+ $operator,
+ implode(', ', $supported_operators)
+ ));
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/Query/QueryTransformer.php b/src/Transformer/Doctrine/ORM/Query/QueryTransformer.php
new file mode 100644
index 00000000..a8447834
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/Query/QueryTransformer.php
@@ -0,0 +1,22 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Query;
+
+use Doctrine\ORM\AbstractQuery;
+use Happyr\DoctrineSpecification\ResultModifier\ResultModifier;
+
+interface QueryTransformer
+{
+ /**
+ * @param ResultModifier $modifier
+ * @param AbstractQuery $query
+ */
+ public function transform(ResultModifier $modifier, AbstractQuery $query);
+}
diff --git a/src/Transformer/Doctrine/ORM/Query/QueryTransformerCollection.php b/src/Transformer/Doctrine/ORM/Query/QueryTransformerCollection.php
new file mode 100644
index 00000000..1e95e1d2
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/Query/QueryTransformerCollection.php
@@ -0,0 +1,50 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Query;
+
+use Doctrine\ORM\AbstractQuery;
+use Happyr\DoctrineSpecification\ResultModifier\ResultModifier;
+
+class QueryTransformerCollection implements QueryTransformer
+{
+ /**
+ * @var QueryTransformer[]
+ */
+ private $transformers = [];
+
+ /**
+ * @param QueryTransformer[] $transformers
+ */
+ public function __construct(array $transformers = [])
+ {
+ foreach ($transformers as $transformer) {
+ $this->addTransformer($transformer);
+ }
+ }
+
+ /**
+ * @param QueryTransformer $transformer
+ */
+ public function addTransformer(QueryTransformer $transformer)
+ {
+ $this->transformers[] = $transformer;
+ }
+
+ /**
+ * @param ResultModifier $modifier
+ * @param AbstractQuery $query
+ */
+ public function transform(ResultModifier $modifier, AbstractQuery $query)
+ {
+ foreach ($this->transformers as $transformer) {
+ $transformer->transform($modifier, $query);
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/Query/ResultModifier/AsArrayTransformer.php b/src/Transformer/Doctrine/ORM/Query/ResultModifier/AsArrayTransformer.php
new file mode 100644
index 00000000..fcebcc9e
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/Query/ResultModifier/AsArrayTransformer.php
@@ -0,0 +1,29 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Query\ResultModifier;
+
+use Doctrine\ORM\AbstractQuery;
+use Happyr\DoctrineSpecification\ResultModifier\AsArray;
+use Happyr\DoctrineSpecification\ResultModifier\ResultModifier;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Query\QueryTransformer;
+
+class AsArrayTransformer implements QueryTransformer
+{
+ /**
+ * @param ResultModifier $modifier
+ * @param AbstractQuery $query
+ */
+ public function transform(ResultModifier $modifier, AbstractQuery $query)
+ {
+ if ($modifier instanceof AsArray) {
+ $query->setHydrationMode(AbstractQuery::HYDRATE_ARRAY);
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/Query/ResultModifier/AsSingleScalarTransformer.php b/src/Transformer/Doctrine/ORM/Query/ResultModifier/AsSingleScalarTransformer.php
new file mode 100644
index 00000000..c7ba3697
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/Query/ResultModifier/AsSingleScalarTransformer.php
@@ -0,0 +1,29 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Query\ResultModifier;
+
+use Doctrine\ORM\AbstractQuery;
+use Happyr\DoctrineSpecification\ResultModifier\AsSingleScalar;
+use Happyr\DoctrineSpecification\ResultModifier\ResultModifier;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Query\QueryTransformer;
+
+class AsSingleScalarTransformer implements QueryTransformer
+{
+ /**
+ * @param ResultModifier $modifier
+ * @param AbstractQuery $query
+ */
+ public function transform(ResultModifier $modifier, AbstractQuery $query)
+ {
+ if ($modifier instanceof AsSingleScalar) {
+ $query->setHydrationMode(AbstractQuery::HYDRATE_SINGLE_SCALAR);
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/Query/ResultModifier/CacheTransformer.php b/src/Transformer/Doctrine/ORM/Query/ResultModifier/CacheTransformer.php
new file mode 100644
index 00000000..b446fea1
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/Query/ResultModifier/CacheTransformer.php
@@ -0,0 +1,29 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Query\ResultModifier;
+
+use Doctrine\ORM\AbstractQuery;
+use Happyr\DoctrineSpecification\ResultModifier\Cache;
+use Happyr\DoctrineSpecification\ResultModifier\ResultModifier;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Query\QueryTransformer;
+
+class CacheTransformer implements QueryTransformer
+{
+ /**
+ * @param ResultModifier $modifier
+ * @param AbstractQuery $query
+ */
+ public function transform(ResultModifier $modifier, AbstractQuery $query)
+ {
+ if ($modifier instanceof Cache) {
+ $query->setResultCacheLifetime($modifier->getCacheLifetime());
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/Query/ResultModifier/ResultModifierCollectionTransformer.php b/src/Transformer/Doctrine/ORM/Query/ResultModifier/ResultModifierCollectionTransformer.php
new file mode 100644
index 00000000..23d81f14
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/Query/ResultModifier/ResultModifierCollectionTransformer.php
@@ -0,0 +1,45 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Query\ResultModifier;
+
+use Doctrine\ORM\AbstractQuery;
+use Happyr\DoctrineSpecification\ResultModifier\ResultModifierCollection;
+use Happyr\DoctrineSpecification\ResultModifier\ResultModifier;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Query\QueryTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Query\QueryTransformerCollection;
+
+class ResultModifierCollectionTransformer implements QueryTransformer
+{
+ /**
+ * @var QueryTransformerCollection
+ */
+ private $collection;
+
+ /**
+ * @param QueryTransformerCollection $collection
+ */
+ public function __construct(QueryTransformerCollection $collection)
+ {
+ $this->collection = $collection;
+ }
+
+ /**
+ * @param ResultModifier $modifier
+ * @param AbstractQuery $query
+ */
+ public function transform(ResultModifier $modifier, AbstractQuery $query)
+ {
+ if ($modifier instanceof ResultModifierCollection) {
+ foreach ($modifier->getModifiers() as $child) {
+ $this->collection->transform($child, $query);
+ }
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/Query/ResultModifier/RoundDateTimeTransformer.php b/src/Transformer/Doctrine/ORM/Query/ResultModifier/RoundDateTimeTransformer.php
new file mode 100644
index 00000000..876bf738
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/Query/ResultModifier/RoundDateTimeTransformer.php
@@ -0,0 +1,42 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Query\ResultModifier;
+
+use Doctrine\ORM\AbstractQuery;
+use Doctrine\ORM\Query\Parameter;
+use Happyr\DoctrineSpecification\ResultModifier\RoundDateTime;
+use Happyr\DoctrineSpecification\ResultModifier\ResultModifier;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Query\QueryTransformer;
+
+class RoundDateTimeTransformer implements QueryTransformer
+{
+ /**
+ * @param ResultModifier $modifier
+ * @param AbstractQuery $query
+ */
+ public function transform(ResultModifier $modifier, AbstractQuery $query)
+ {
+ if ($modifier instanceof RoundDateTime) {
+ foreach ($query->getParameters() as $parameter) {
+ /* @var $parameter Parameter */
+ if ($parameter->getValue() instanceof \DateTimeInterface) {
+ // round down so that the results do not include data that should not be there.
+ $date = clone $parameter->getValue();
+ $date = $date->setTimestamp(
+ floor($date->getTimestamp() / $modifier->getRoundSeconds()) *
+ $modifier->getRoundSeconds()
+ );
+
+ $query->setParameter($parameter->getName(), $date, $parameter->getType());
+ }
+ }
+ }
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/ComparisonTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/ComparisonTransformer.php
new file mode 100644
index 00000000..d7293731
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/ComparisonTransformer.php
@@ -0,0 +1,77 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter;
+
+use Doctrine\ORM\Query\Expr\Comparison as DoctrineComparison;
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\Filter\Comparison;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Exception\InvalidArgumentException;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ValueConverter;
+
+abstract class ComparisonTransformer implements QueryBuilderTransformer
+{
+ const EQ = DoctrineComparison::EQ;
+ const NEQ = DoctrineComparison::NEQ;
+ const LT = DoctrineComparison::LT;
+ const LTE = DoctrineComparison::LTE;
+ const GT = DoctrineComparison::GT;
+ const GTE = DoctrineComparison::GTE;
+
+ /**
+ * @var array
+ */
+ private static $operators = [
+ self::EQ,
+ self::NEQ,
+ self::LT,
+ self::LTE,
+ self::GT,
+ self::GTE,
+ ];
+
+ /**
+ * @param Comparison $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ * @param string $operator
+ *
+ * @return string
+ */
+ protected function getCondition(Comparison $specification, QueryBuilder $qb, $dqlAlias, $operator)
+ {
+ if (!in_array($operator, self::$operators)) {
+ throw InvalidArgumentException::invalidComparisonOperator(self::$operators, $operator);
+ }
+
+ $paramName = $this->getParameterName($qb);
+ $value = ValueConverter::convertToDatabaseValue($specification->getValue(), $qb);
+
+ $qb->setParameter($paramName, $value);
+
+ return (string) new DoctrineComparison(
+ sprintf('%s.%s', $dqlAlias, $specification->getField()),
+ $operator,
+ sprintf(':%s', $paramName)
+ );
+ }
+
+ /**
+ * Get a good unique parameter name.
+ *
+ * @param QueryBuilder $qb
+ *
+ * @return string
+ */
+ private function getParameterName(QueryBuilder $qb)
+ {
+ return sprintf('comparison_%d', $qb->getParameters()->count());
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/EqualsTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/EqualsTransformer.php
new file mode 100644
index 00000000..e8cc74fe
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/EqualsTransformer.php
@@ -0,0 +1,33 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\Filter\Equals;
+use Happyr\DoctrineSpecification\Specification;
+
+class EqualsTransformer extends ComparisonTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof Equals) {
+ return $this->getCondition($specification, $qb, $dqlAlias, self::EQ);
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/GreaterOrEqualThanTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/GreaterOrEqualThanTransformer.php
new file mode 100644
index 00000000..c3e495db
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/GreaterOrEqualThanTransformer.php
@@ -0,0 +1,33 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\Filter\GreaterOrEqualThan;
+use Happyr\DoctrineSpecification\Specification;
+
+class GreaterOrEqualThanTransformer extends ComparisonTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof GreaterOrEqualThan) {
+ return $this->getCondition($specification, $qb, $dqlAlias, self::GTE);
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/GreaterThanTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/GreaterThanTransformer.php
new file mode 100644
index 00000000..88431bda
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/GreaterThanTransformer.php
@@ -0,0 +1,33 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\Filter\GreaterThan;
+use Happyr\DoctrineSpecification\Specification;
+
+class GreaterThanTransformer extends ComparisonTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof GreaterThan) {
+ return $this->getCondition($specification, $qb, $dqlAlias, self::GT);
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/InTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/InTransformer.php
new file mode 100644
index 00000000..b4be76f2
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/InTransformer.php
@@ -0,0 +1,63 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\Filter\In;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ValueConverter;
+
+class InTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof In) {
+ $paramName = $this->getParameterName($qb);
+ $value = $specification->getValue();
+
+ if (is_array($value)) {
+ foreach ($value as $k => $v) {
+ $value[$k] = ValueConverter::convertToDatabaseValue($v, $qb);
+ }
+ } else {
+ $value = ValueConverter::convertToDatabaseValue($value, $qb);
+ }
+
+ $qb->setParameter($paramName, $value);
+
+ return (string) $qb->expr()->in(
+ sprintf('%s.%s', $dqlAlias, $specification->getField()),
+ sprintf(':%s', $paramName)
+ );
+ }
+
+ return null;
+ }
+
+ /**
+ * Get a good unique parameter name.
+ *
+ * @param QueryBuilder $qb
+ *
+ * @return string
+ */
+ private function getParameterName(QueryBuilder $qb)
+ {
+ return sprintf('in_%d', $qb->getParameters()->count());
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/InstanceOfXTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/InstanceOfXTransformer.php
new file mode 100644
index 00000000..5dfa127d
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/InstanceOfXTransformer.php
@@ -0,0 +1,34 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\Filter\InstanceOfX;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformer;
+
+class InstanceOfXTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof InstanceOfX) {
+ return sprintf('%s INSTANCE OF %s', $dqlAlias, $specification->getValue());
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/IsNotNullTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/IsNotNullTransformer.php
new file mode 100644
index 00000000..dc04a521
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/IsNotNullTransformer.php
@@ -0,0 +1,36 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\Filter\IsNotNull;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformer;
+
+class IsNotNullTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof IsNotNull) {
+ return (string) $qb->expr()->isNotNull(
+ sprintf('%s.%s', $dqlAlias, $specification->getField())
+ );
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/IsNullTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/IsNullTransformer.php
new file mode 100644
index 00000000..935b62b3
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/IsNullTransformer.php
@@ -0,0 +1,36 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\Filter\IsNull;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformer;
+
+class IsNullTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof IsNull) {
+ return (string) $qb->expr()->isNull(
+ sprintf('%s.%s', $dqlAlias, $specification->getField())
+ );
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/LessOrEqualThanTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/LessOrEqualThanTransformer.php
new file mode 100644
index 00000000..23039bea
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/LessOrEqualThanTransformer.php
@@ -0,0 +1,33 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\Filter\LessOrEqualThan;
+use Happyr\DoctrineSpecification\Specification;
+
+class LessOrEqualThanTransformer extends ComparisonTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof LessOrEqualThan) {
+ return $this->getCondition($specification, $qb, $dqlAlias, self::LTE);
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/LessThanTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/LessThanTransformer.php
new file mode 100644
index 00000000..e60c0cd8
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/LessThanTransformer.php
@@ -0,0 +1,33 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\Filter\LessThan;
+use Happyr\DoctrineSpecification\Specification;
+
+class LessThanTransformer extends ComparisonTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof LessThan) {
+ return $this->getCondition($specification, $qb, $dqlAlias, self::LT);
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/LikeTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/LikeTransformer.php
new file mode 100644
index 00000000..402761f2
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/LikeTransformer.php
@@ -0,0 +1,64 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter;
+
+use Doctrine\ORM\Query\Expr\Comparison;
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\Filter\Like;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ValueConverter;
+
+class LikeTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof Like) {
+ $paramName = $this->getParameterName($qb);
+ $value = ValueConverter::convertToDatabaseValue($specification->getValue(), $qb);
+
+ if ($specification->getFormat() | Like::ENDS_WITH) {
+ $value = '%'.$value;
+ }
+ if ($specification->getFormat() | Like::STARTS_WITH) {
+ $value = $value.'%';
+ }
+
+ $qb->setParameter($paramName, $value);
+
+ return (string) new Comparison(
+ sprintf('%s.%s', $dqlAlias, $specification->getField()),
+ 'LIKE',
+ sprintf(':%s', $paramName)
+ );
+ }
+
+ return null;
+ }
+
+ /**
+ * Get a good unique parameter name.
+ *
+ * @param QueryBuilder $qb
+ *
+ * @return string
+ */
+ private function getParameterName(QueryBuilder $qb)
+ {
+ return sprintf('like_%d', $qb->getParameters()->count());
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/Logic/AndXTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/Logic/AndXTransformer.php
new file mode 100644
index 00000000..e9891be9
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/Logic/AndXTransformer.php
@@ -0,0 +1,46 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter\Logic;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\Filter\Logic\AndX;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformerCollection;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformerCollectionAware;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformerCollectionAwareTrait;
+
+class AndXTransformer implements QueryBuilderTransformerCollectionAware
+{
+ use QueryBuilderTransformerCollectionAwareTrait;
+
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof AndX && $this->collection instanceof QueryBuilderTransformerCollection) {
+ $andX = $qb->expr()->andX();
+
+ foreach ($specification->getFilters() as $filter) {
+ if ($condition = $this->collection->transform($filter, $qb, $dqlAlias)) {
+ $andX->add($condition);
+ }
+ }
+
+ return $andX->count() ? (string) $andX : null;
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/Logic/NotTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/Logic/NotTransformer.php
new file mode 100644
index 00000000..c577aa7e
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/Logic/NotTransformer.php
@@ -0,0 +1,41 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter\Logic;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\Filter\Logic\Not;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformerCollection;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformerCollectionAware;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformerCollectionAwareTrait;
+
+class NotTransformer implements QueryBuilderTransformerCollectionAware
+{
+ use QueryBuilderTransformerCollectionAwareTrait;
+
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof Not &&
+ $this->collection instanceof QueryBuilderTransformerCollection &&
+ ($condition = $this->collection->transform($specification->getFilter(), $qb, $dqlAlias))
+ ) {
+ return $qb->expr()->not($condition);
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/Logic/OrXTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/Logic/OrXTransformer.php
new file mode 100644
index 00000000..56431c19
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/Logic/OrXTransformer.php
@@ -0,0 +1,46 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter\Logic;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\Filter\Logic\OrX;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformerCollection;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformerCollectionAware;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformerCollectionAwareTrait;
+
+class OrXTransformer implements QueryBuilderTransformerCollectionAware
+{
+ use QueryBuilderTransformerCollectionAwareTrait;
+
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof OrX && $this->collection instanceof QueryBuilderTransformerCollection) {
+ $orX = $qb->expr()->orX();
+
+ foreach ($specification->getFilters() as $filter) {
+ if ($condition = $this->collection->transform($filter, $qb, $dqlAlias)) {
+ $orX->add($condition);
+ }
+ }
+
+ return $orX->count() ? (string) $orX : null;
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/NotEqualsTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/NotEqualsTransformer.php
new file mode 100644
index 00000000..d074e75c
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/Filter/NotEqualsTransformer.php
@@ -0,0 +1,33 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\Filter\NotEquals;
+use Happyr\DoctrineSpecification\Specification;
+
+class NotEqualsTransformer extends ComparisonTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof NotEquals) {
+ return $this->getCondition($specification, $qb, $dqlAlias, self::NEQ);
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/QueryBuilderTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/QueryBuilderTransformer.php
new file mode 100644
index 00000000..86f1a80b
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/QueryBuilderTransformer.php
@@ -0,0 +1,27 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\Specification;
+
+interface QueryBuilderTransformer
+{
+ /**
+ * Return a condition string or NULL if the specification is not a filter.
+ *
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias);
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/QueryBuilderTransformerCollection.php b/src/Transformer/Doctrine/ORM/QueryBuilder/QueryBuilderTransformerCollection.php
new file mode 100644
index 00000000..c5490fc9
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/QueryBuilderTransformerCollection.php
@@ -0,0 +1,61 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\Specification;
+
+class QueryBuilderTransformerCollection implements QueryBuilderTransformer
+{
+ /**
+ * @var QueryBuilderTransformer[]
+ */
+ private $transformers = [];
+
+ /**
+ * @param QueryBuilderTransformer[] $transformers
+ */
+ public function __construct(array $transformers = [])
+ {
+ foreach ($transformers as $transformer) {
+ $this->addTransformer($transformer);
+ }
+ }
+
+ /**
+ * @param QueryBuilderTransformer $transformer
+ */
+ public function addTransformer(QueryBuilderTransformer $transformer)
+ {
+ $this->transformers[] = $transformer;
+
+ if ($transformer instanceof QueryBuilderTransformerCollectionAware) {
+ $transformer->setCollection($this);
+ }
+ }
+
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ foreach ($this->transformers as $transformer) {
+ if ($condition = $transformer->transform($specification, $qb, $dqlAlias)) {
+ return $condition;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/QueryBuilderTransformerCollectionAware.php b/src/Transformer/Doctrine/ORM/QueryBuilder/QueryBuilderTransformerCollectionAware.php
new file mode 100644
index 00000000..f4256e64
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/QueryBuilderTransformerCollectionAware.php
@@ -0,0 +1,18 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder;
+
+interface QueryBuilderTransformerCollectionAware extends QueryBuilderTransformer
+{
+ /**
+ * @param QueryBuilderTransformerCollection $collection
+ */
+ public function setCollection(QueryBuilderTransformerCollection $collection);
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/QueryBuilderTransformerCollectionAwareTrait.php b/src/Transformer/Doctrine/ORM/QueryBuilder/QueryBuilderTransformerCollectionAwareTrait.php
new file mode 100644
index 00000000..db2fd5d4
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/QueryBuilderTransformerCollectionAwareTrait.php
@@ -0,0 +1,26 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder;
+
+trait QueryBuilderTransformerCollectionAwareTrait
+{
+ /**
+ * @var QueryBuilderTransformerCollection
+ */
+ protected $collection;
+
+ /**
+ * @param QueryBuilderTransformerCollection $collection
+ */
+ public function setCollection(QueryBuilderTransformerCollection $collection)
+ {
+ $this->collection = $collection;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/QueryModifier/AbstractJoinTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/QueryModifier/AbstractJoinTransformer.php
new file mode 100644
index 00000000..56e3a71c
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/QueryModifier/AbstractJoinTransformer.php
@@ -0,0 +1,50 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryModifier;
+
+use Doctrine\ORM\Query\Expr\Join;
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\Filter\Filter;
+use Happyr\DoctrineSpecification\QueryModifier\AbstractJoin;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformerCollection;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformerCollectionAware;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformerCollectionAwareTrait;
+
+abstract class AbstractJoinTransformer implements QueryBuilderTransformerCollectionAware
+{
+ use QueryBuilderTransformerCollectionAwareTrait;
+
+ /**
+ * @param AbstractJoin $specification
+ * @param QueryBuilder $qb
+ *
+ * @return string|null
+ */
+ protected function getCondition(AbstractJoin $specification, QueryBuilder $qb)
+ {
+ if (!($specification->getCondition() instanceof Filter) ||
+ !($this->collection instanceof QueryBuilderTransformerCollection)
+ ) {
+ return null;
+ }
+
+ return $this->collection->transform($specification->getCondition(), $qb, $specification->getAlias());
+ }
+
+ /**
+ * @param AbstractJoin $specification
+ *
+ * @return string
+ */
+ protected function getConditionType(AbstractJoin $specification)
+ {
+ return $specification->getConditionType() == AbstractJoin::ON ? Join::ON : Join::WITH;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/QueryModifier/GroupByTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/QueryModifier/GroupByTransformer.php
new file mode 100644
index 00000000..74023adf
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/QueryModifier/GroupByTransformer.php
@@ -0,0 +1,34 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryModifier;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\QueryModifier\GroupBy;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformer;
+
+class GroupByTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof GroupBy) {
+ $qb->addGroupBy(sprintf('%s.%s', $dqlAlias, $specification->getField()));
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/QueryModifier/HavingTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/QueryModifier/HavingTransformer.php
new file mode 100644
index 00000000..0cc03a41
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/QueryModifier/HavingTransformer.php
@@ -0,0 +1,41 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryModifier;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\QueryModifier\Having;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformerCollection;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformerCollectionAware;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformerCollectionAwareTrait;
+
+class HavingTransformer implements QueryBuilderTransformerCollectionAware
+{
+ use QueryBuilderTransformerCollectionAwareTrait;
+
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof Having &&
+ $this->collection instanceof QueryBuilderTransformerCollection &&
+ ($condition = $this->collection->transform($specification->getFilter(), $qb, $dqlAlias))
+ ) {
+ $qb->having($condition);
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/QueryModifier/InnerJoinTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/QueryModifier/InnerJoinTransformer.php
new file mode 100644
index 00000000..9c6cf589
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/QueryModifier/InnerJoinTransformer.php
@@ -0,0 +1,42 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryModifier;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\QueryModifier\InnerJoin;
+use Happyr\DoctrineSpecification\Specification;
+
+class InnerJoinTransformer extends AbstractJoinTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof InnerJoin) {
+ if ($condition = $this->getCondition($specification, $qb)) {
+ $qb->innerJoin(
+ sprintf('%s.%s', $dqlAlias, $specification->getField()),
+ $specification->getAlias(),
+ $this->getConditionType($specification),
+ $condition
+ );
+ } else {
+ $qb->innerJoin(sprintf('%s.%s', $dqlAlias, $specification->getField()), $specification->getAlias());
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/QueryModifier/JoinTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/QueryModifier/JoinTransformer.php
new file mode 100644
index 00000000..b6ffb161
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/QueryModifier/JoinTransformer.php
@@ -0,0 +1,42 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryModifier;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\QueryModifier\Join;
+use Happyr\DoctrineSpecification\Specification;
+
+class JoinTransformer extends AbstractJoinTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof Join) {
+ if ($condition = $this->getCondition($specification, $qb)) {
+ $qb->join(
+ sprintf('%s.%s', $dqlAlias, $specification->getField()),
+ $specification->getAlias(),
+ $this->getConditionType($specification),
+ $condition
+ );
+ } else {
+ $qb->join(sprintf('%s.%s', $dqlAlias, $specification->getField()), $specification->getAlias());
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/QueryModifier/LeftJoinTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/QueryModifier/LeftJoinTransformer.php
new file mode 100644
index 00000000..9940e611
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/QueryModifier/LeftJoinTransformer.php
@@ -0,0 +1,42 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryModifier;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\QueryModifier\LeftJoin;
+use Happyr\DoctrineSpecification\Specification;
+
+class LeftJoinTransformer extends AbstractJoinTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof LeftJoin) {
+ if ($condition = $this->getCondition($specification, $qb)) {
+ $qb->leftJoin(
+ sprintf('%s.%s', $dqlAlias, $specification->getField()),
+ $specification->getAlias(),
+ $this->getConditionType($specification),
+ $condition
+ );
+ } else {
+ $qb->leftJoin(sprintf('%s.%s', $dqlAlias, $specification->getField()), $specification->getAlias());
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/QueryModifier/QueryModifierCollectionTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/QueryModifier/QueryModifierCollectionTransformer.php
new file mode 100644
index 00000000..1b872656
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/QueryModifier/QueryModifierCollectionTransformer.php
@@ -0,0 +1,43 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryModifier;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\QueryModifier\QueryModifierCollection;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformerCollection;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformerCollectionAware;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformerCollectionAwareTrait;
+
+class QueryModifierCollectionTransformer implements QueryBuilderTransformerCollectionAware
+{
+ use QueryBuilderTransformerCollectionAwareTrait;
+
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof QueryModifierCollection &&
+ $this->collection instanceof QueryBuilderTransformerCollection
+ ) {
+ foreach ($specification->getModifiers() as $modifier) {
+ // query modifiers not return a conditions
+ $this->collection->transform($modifier, $qb, $dqlAlias);
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/ResultManagement/CountOfTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/ResultManagement/CountOfTransformer.php
new file mode 100644
index 00000000..4a90d732
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/ResultManagement/CountOfTransformer.php
@@ -0,0 +1,34 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\ResultManagement;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\ResultManagement\CountOf;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformer;
+
+class CountOfTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof CountOf) {
+ $qb->select(sprintf('COUNT(%s)', $dqlAlias));
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/ResultManagement/LimitTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/ResultManagement/LimitTransformer.php
new file mode 100644
index 00000000..be3f1cf2
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/ResultManagement/LimitTransformer.php
@@ -0,0 +1,34 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\ResultManagement;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\ResultManagement\Limit;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformer;
+
+class LimitTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof Limit) {
+ $qb->setMaxResults($specification->getLimit());
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/ResultManagement/OffsetTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/ResultManagement/OffsetTransformer.php
new file mode 100644
index 00000000..e7e96ccf
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/ResultManagement/OffsetTransformer.php
@@ -0,0 +1,34 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\ResultManagement;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\ResultManagement\Offset;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformer;
+
+class OffsetTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof Offset) {
+ $qb->setFirstResult($specification->getOffset());
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/ResultManagement/OrderByTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/ResultManagement/OrderByTransformer.php
new file mode 100644
index 00000000..2939527f
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/ResultManagement/OrderByTransformer.php
@@ -0,0 +1,37 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\ResultManagement;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\ResultManagement\OrderBy;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformer;
+
+class OrderByTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof OrderBy) {
+ $qb->addOrderBy(
+ sprintf('%s.%s', $dqlAlias, $specification->getField()),
+ $specification->getOrder()
+ );
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/ResultManagement/SliceTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/ResultManagement/SliceTransformer.php
new file mode 100644
index 00000000..0d1db8c2
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/ResultManagement/SliceTransformer.php
@@ -0,0 +1,38 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\ResultManagement;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\ResultManagement\Slice;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformer;
+
+class SliceTransformer implements QueryBuilderTransformer
+{
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof Slice) {
+ $qb->setMaxResults($specification->getSliceSize());
+
+ if ($specification->getSliceNumber() > 0) {
+ $qb->setFirstResult($specification->getSliceNumber() * $specification->getSliceSize());
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/src/Transformer/Doctrine/ORM/QueryBuilder/SpecificationCollectionTransformer.php b/src/Transformer/Doctrine/ORM/QueryBuilder/SpecificationCollectionTransformer.php
new file mode 100644
index 00000000..9c390fff
--- /dev/null
+++ b/src/Transformer/Doctrine/ORM/QueryBuilder/SpecificationCollectionTransformer.php
@@ -0,0 +1,45 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder;
+
+use Doctrine\ORM\QueryBuilder;
+use Happyr\DoctrineSpecification\Specification;
+use Happyr\DoctrineSpecification\SpecificationCollection;
+
+class SpecificationCollectionTransformer implements QueryBuilderTransformerCollectionAware
+{
+ use QueryBuilderTransformerCollectionAwareTrait;
+
+ /**
+ * @param Specification $specification
+ * @param QueryBuilder $qb
+ * @param string $dqlAlias
+ *
+ * @return string|null
+ */
+ public function transform(Specification $specification, QueryBuilder $qb, $dqlAlias)
+ {
+ if ($specification instanceof SpecificationCollection &&
+ $this->collection instanceof QueryBuilderTransformerCollection
+ ) {
+ $andX = $qb->expr()->andX();
+
+ foreach ($specification->getSpecifications() as $specification) {
+ if ($condition = $this->collection->transform($specification, $qb, $dqlAlias)) {
+ $andX->add($condition);
+ }
+ }
+
+ return $andX->count() ? (string) $andX : null;
+ }
+
+ return null;
+ }
+}
diff --git a/src/RepositoryFactory.php b/src/Transformer/Doctrine/ORM/RepositoryFactory.php
similarity index 50%
rename from src/RepositoryFactory.php
rename to src/Transformer/Doctrine/ORM/RepositoryFactory.php
index 670f9892..bdc4b3f8 100644
--- a/src/RepositoryFactory.php
+++ b/src/Transformer/Doctrine/ORM/RepositoryFactory.php
@@ -1,9 +1,17 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
-namespace Happyr\DoctrineSpecification;
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine\ORM;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
+use Doctrine\ORM\Repository\RepositoryFactory as DoctrineRepositoryFactory;
/**
* Factory class for creating EntitySpecificationRepository instances.
@@ -11,8 +19,21 @@
* Provides an implementation of RepositoryFactory so that the
* default repository type in Doctrine can easily be replaced.
*/
-class RepositoryFactory implements \Doctrine\ORM\Repository\RepositoryFactory
+class RepositoryFactory implements DoctrineRepositoryFactory
{
+ /**
+ * @var DoctrineORMTransformer
+ */
+ private $transformer;
+
+ /**
+ * @param DoctrineORMTransformer $transformer
+ */
+ public function __construct(DoctrineORMTransformer $transformer)
+ {
+ $this->transformer = $transformer;
+ }
+
/**
* Gets the repository for an entity class.
*
@@ -25,7 +46,8 @@ public function getRepository(EntityManagerInterface $entityManager, $entityName
{
return new EntitySpecificationRepository(
$entityManager,
- $entityManager->getClassMetadata($entityName)
+ $entityManager->getClassMetadata($entityName),
+ $this->transformer
);
}
}
diff --git a/src/ValueConverter.php b/src/Transformer/Doctrine/ValueConverter.php
similarity index 68%
rename from src/ValueConverter.php
rename to src/Transformer/Doctrine/ValueConverter.php
index 37502828..d939966a 100644
--- a/src/ValueConverter.php
+++ b/src/Transformer/Doctrine/ValueConverter.php
@@ -1,6 +1,13 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
-namespace Happyr\DoctrineSpecification;
+namespace Happyr\DoctrineSpecification\Transformer\Doctrine;
use Doctrine\ORM\QueryBuilder;
diff --git a/tests/EntitySpecificationRepositorySpec.php b/tests/EntitySpecificationRepositorySpec.php
deleted file mode 100644
index 5da49b5f..00000000
--- a/tests/EntitySpecificationRepositorySpec.php
+++ /dev/null
@@ -1,255 +0,0 @@
-beConstructedWith($entityManager, $classMetadata);
- }
-
- public function it_should_modify_query(
- QueryModifier $specification,
- EntityManager $entityManager,
- QueryBuilder $qb,
- AbstractQuery $query
- ) {
- $this->prepareEntityManagerStub($entityManager, $qb);
- $this->prepareQueryBuilderStub($qb, $query);
- $query->execute()->willReturn($this->result);
-
- $specification->modify($qb, $this->alias)->shouldBeCalled();
-
- $this->match($specification);
- }
-
- public function it_should_apply_filter(
- Filter $specification,
- EntityManager $entityManager,
- QueryBuilder $qb,
- AbstractQuery $query
- ) {
- $this->prepareEntityManagerStub($entityManager, $qb);
- $this->prepareQueryBuilderStub($qb, $query);
- $specification->getFilter($qb, $this->alias)->willReturn($this->expression);
-
- $qb->andWhere($this->expression)->willReturn($qb);
- $qb->where()->shouldNotBeCalled();
-
- $this->match($specification);
- }
-
- public function it_should_skip_apply_empty_specification(
- EntityManager $entityManager,
- QueryBuilder $qb,
- AbstractQuery $query
- ) {
- $this->prepareEntityManagerStub($entityManager, $qb);
- $this->prepareQueryBuilderStub($qb, $query);
-
- $qb->andWhere()->shouldNotBeCalled();
- $qb->where()->shouldNotBeCalled();
-
- $this->match(null);
- }
-
- public function it_should_throw_exception_when_apply_not_specification(
- EntityManager $entityManager,
- QueryBuilder $qb,
- AbstractQuery $query
- ) {
- $this->prepareEntityManagerStub($entityManager, $qb);
- $this->prepareQueryBuilderStub($qb, $query);
-
- $this->shouldThrow('\InvalidArgumentException')->duringMatch(new \stdClass());
- $this->shouldThrow('\InvalidArgumentException')->duringMatch(['fake', 'array']);
- $this->shouldThrow('\InvalidArgumentException')->duringMatch('fake');
- }
-
- public function it_matches_a_specification_with_empty_filter(
- Specification $specification,
- EntityManager $entityManager,
- QueryBuilder $qb,
- AbstractQuery $query
- ) {
- $this->prepareEntityManagerStub($entityManager, $qb);
- $this->prepareQueryBuilderStub($qb, $query);
- $query->execute()->willReturn($this->result);
-
- $qb->andWhere()->shouldNotBeCalled();
- $qb->where()->shouldNotBeCalled();
-
- $this->match($specification)->shouldReturn($this->result);
- }
-
- public function it_matches_a_specification_without_result_modifier(
- Specification $specification,
- EntityManager $entityManager,
- QueryBuilder $qb,
- AbstractQuery $query
- ) {
- $this->prepareStubs($specification, $entityManager, $qb, $query);
- $query->execute()->willReturn($this->result);
-
- $specification->modify($qb, $this->alias)->shouldBeCalled();
-
- $this->match($specification)->shouldReturn($this->result);
- }
-
- public function it_matches_a_single_result_without_result_modifier(
- Specification $specification,
- EntityManager $entityManager,
- QueryBuilder $qb,
- AbstractQuery $query
- ) {
- $singleResult = new \stdClass();
-
- $this->prepareStubs($specification, $entityManager, $qb, $query);
-
- $specification->modify($qb, $this->alias)->shouldBeCalled();
-
- $query->getSingleResult()->willReturn($singleResult);
-
- $this->matchSingleResult($specification)->shouldReturn($singleResult);
- }
-
- public function it_throws_exception_when_expecting_single_result_finding_none_without_result_modifier(
- Specification $specification,
- EntityManager $entityManager,
- QueryBuilder $qb,
- AbstractQuery $query
- ) {
- $this->prepareStubs($specification, $entityManager, $qb, $query);
-
- $specification->modify($qb, $this->alias)->shouldBeCalled();
-
- $query->getSingleResult()->willThrow(new NoResultException());
-
- $this->shouldThrow('Happyr\DoctrineSpecification\Exception\NoResultException')->duringMatchSingleResult($specification);
- }
-
- public function it_throws_exception_when_expecting_single_result_finding_multiple_without_result_modifier(
- Specification $specification,
- EntityManager $entityManager,
- QueryBuilder $qb,
- AbstractQuery $query
- ) {
- $this->prepareStubs($specification, $entityManager, $qb, $query);
-
- $specification->modify($qb, $this->alias)->shouldBeCalled();
-
- $query->getSingleResult()->willThrow(new NonUniqueResultException());
-
- $this->shouldThrow('Happyr\DoctrineSpecification\Exception\NonUniqueResultException')->duringMatchSingleResult($specification);
- }
-
- public function it_matches_a_single_result_when_expecting_one_or_null_without_result_modifier(
- Specification $specification,
- EntityManager $entityManager,
- QueryBuilder $qb,
- AbstractQuery $query
- ) {
- $singleResult = new \stdClass();
-
- $this->prepareStubs($specification, $entityManager, $qb, $query);
-
- $specification->modify($qb, $this->alias)->shouldBeCalled();
-
- $query->getSingleResult()->willReturn($singleResult);
-
- $this->matchOneOrNullResult($specification)->shouldReturn($singleResult);
- }
-
- public function it_matches_null_when_expecting_one_or_null_without_result_modifier(
- Specification $specification,
- EntityManager $entityManager,
- QueryBuilder $qb,
- AbstractQuery $query
- ) {
- $this->prepareStubs($specification, $entityManager, $qb, $query);
-
- $specification->modify($qb, $this->alias)->shouldBeCalled();
-
- $query->getSingleResult()->willThrow(new NonUniqueResultException());
-
- $this->shouldThrow('Happyr\DoctrineSpecification\Exception\NonUniqueResultException')->duringMatchOneOrNullResult($specification);
- }
-
- public function it_throws_exception_when_expecting_one_or_null_finding_multiple_without_result_modifier(
- Specification $specification,
- EntityManager $entityManager,
- QueryBuilder $qb,
- AbstractQuery $query
- ) {
- $this->prepareStubs($specification, $entityManager, $qb, $query);
-
- $specification->modify($qb, $this->alias)->shouldBeCalled();
-
- $query->getSingleResult()->willThrow(new NonUniqueResultException());
-
- $this->shouldThrow('Happyr\DoctrineSpecification\Exception\UnexpectedResultException')->duringMatchOneOrNullResult($specification);
- }
-
- public function it_matches_a_specification_with_result_modifier(
- Specification $specification,
- EntityManager $entityManager,
- QueryBuilder $qb,
- AbstractQuery $query,
- ResultModifier $modifier
- ) {
- $this->prepareStubs($specification, $entityManager, $qb, $query);
- $query->execute()->willReturn($this->result);
-
- $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)
- {
- $this->prepareEntityManagerStub($entityManager, $qb);
- $this->prepareSpecificationStub($specification, $qb);
- $this->prepareQueryBuilderStub($qb, $query);
- }
-
- private function prepareEntityManagerStub(EntityManager $entityManager, QueryBuilder $qb)
- {
- $entityManager->createQueryBuilder()->willReturn($qb);
- }
-
- private function prepareSpecificationStub(Specification $specification, QueryBuilder $qb)
- {
- $specification->getFilter($qb, $this->alias)->willReturn($this->expression);
- }
-
- private function prepareQueryBuilderStub(QueryBuilder $qb, Query $query)
- {
- $qb->from(Argument::any(), $this->alias, null)->willReturn($qb);
- $qb->select($this->alias)->willReturn($qb);
- $qb->andWhere($this->expression)->willReturn($qb);
- $qb->getQuery()->willReturn($query);
- }
-}
diff --git a/tests/Filter/ComparisonSpec.php b/tests/Filter/ComparisonSpec.php
deleted file mode 100644
index dbb7ad3d..00000000
--- a/tests/Filter/ComparisonSpec.php
+++ /dev/null
@@ -1,53 +0,0 @@
-beConstructedWith(Comparison::GT, 'age', 18, 'a');
- }
-
- public function it_is_an_expression()
- {
- $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Filter\Filter');
- }
-
- public 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');
- }
-
- public 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');
- }
-
- public function it_validates_operator()
- {
- $this->shouldThrow('Happyr\DoctrineSpecification\Exception\InvalidArgumentException')->during('__construct', array('==', 'age', 18, null));
- }
-}
diff --git a/tests/Filter/InSpec.php b/tests/Filter/InSpec.php
index 50e49e2a..0f0a7e28 100644
--- a/tests/Filter/InSpec.php
+++ b/tests/Filter/InSpec.php
@@ -1,10 +1,14 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
namespace tests\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;
@@ -15,11 +19,16 @@ class InSpec extends ObjectBehavior
{
private $field = 'foobar';
- private $value = array('bar', 'baz');
+ private $value = ['bar', 'baz'];
public function let()
{
- $this->beConstructedWith($this->field, $this->value, 'a');
+ $this->beConstructedWith($this->field, $this->value);
+ }
+
+ public function it_is_initializable()
+ {
+ $this->shouldHaveType('Happyr\DoctrineSpecification\Filter\In');
}
public function it_is_an_expression()
@@ -27,17 +36,13 @@ public function it_is_an_expression()
$this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Filter\Filter');
}
- public function it_returns_expression_func_object(QueryBuilder $qb, ArrayCollection $parameters, Expr $expr)
+ public function it_should_return_field()
{
- $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($this->field);
+ }
- $this->getFilter($qb, null);
+ public function it_should_return_value()
+ {
+ $this->getValue()->shouldReturn($this->value);
}
}
diff --git a/tests/Filter/InstanceOfXSpec.php b/tests/Filter/InstanceOfXSpec.php
index 669e8ce7..39808384 100644
--- a/tests/Filter/InstanceOfXSpec.php
+++ b/tests/Filter/InstanceOfXSpec.php
@@ -1,8 +1,14 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
namespace tests\Happyr\DoctrineSpecification\Filter;
-use Doctrine\ORM\QueryBuilder;
use Happyr\DoctrineSpecification\Filter\InstanceOfX;
use PhpSpec\ObjectBehavior;
@@ -11,9 +17,11 @@
*/
class InstanceOfXSpec extends ObjectBehavior
{
+ private $value = 'My\Model';
+
public function let()
{
- $this->beConstructedWith('My\Model', 'o');
+ $this->beConstructedWith($this->value);
}
public function it_is_initializable()
@@ -26,8 +34,8 @@ public function it_is_an_expression()
$this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Filter\Filter');
}
- public function it_returns_expression_func_object(QueryBuilder $qb)
+ public function it_should_return_value()
{
- $this->getFilter($qb, null)->shouldReturn('o INSTANCE OF My\Model');
+ $this->getValue()->shouldReturn($this->value);
}
}
diff --git a/tests/Filter/IsNotNullSpec.php b/tests/Filter/IsNotNullSpec.php
index caedd150..b79c4b3e 100644
--- a/tests/Filter/IsNotNullSpec.php
+++ b/tests/Filter/IsNotNullSpec.php
@@ -1,9 +1,14 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
namespace tests\Happyr\DoctrineSpecification\Filter;
-use Doctrine\ORM\Query\Expr;
-use Doctrine\ORM\QueryBuilder;
use Happyr\DoctrineSpecification\Filter\IsNotNull;
use PhpSpec\ObjectBehavior;
@@ -14,38 +19,23 @@ class IsNotNullSpec extends ObjectBehavior
{
private $field = 'foobar';
- private $dqlAlias = 'a';
-
public function let()
{
- $this->beConstructedWith($this->field, $this->dqlAlias);
+ $this->beConstructedWith($this->field);
}
- public function it_is_an_expression()
+ public function it_is_initializable()
{
- $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Filter\Filter');
+ $this->shouldHaveType('Happyr\DoctrineSpecification\Filter\IsNotNull');
}
- /**
- * returns expression func object.
- */
- public function it_calls_not_null(QueryBuilder $qb, Expr $expr)
+ public function it_is_an_expression()
{
- $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\Filter');
}
- public function it_uses_dql_alias_if_passed(QueryBuilder $qb, Expr $expr)
+ public function it_should_return_field()
{
- $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($this->field);
}
}
diff --git a/tests/Filter/IsNullSpec.php b/tests/Filter/IsNullSpec.php
index 72174537..3a749334 100644
--- a/tests/Filter/IsNullSpec.php
+++ b/tests/Filter/IsNullSpec.php
@@ -1,9 +1,14 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
namespace tests\Happyr\DoctrineSpecification\Filter;
-use Doctrine\ORM\Query\Expr;
-use Doctrine\ORM\QueryBuilder;
use Happyr\DoctrineSpecification\Filter\IsNull;
use PhpSpec\ObjectBehavior;
@@ -14,38 +19,23 @@ class IsNullSpec extends ObjectBehavior
{
private $field = 'foobar';
- private $dqlAlias = 'a';
-
public function let()
{
- $this->beConstructedWith($this->field, $this->dqlAlias);
+ $this->beConstructedWith($this->field);
}
- public function it_is_an_expression()
+ public function it_is_initializable()
{
- $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Filter\Filter');
+ $this->shouldHaveType('Happyr\DoctrineSpecification\Filter\IsNull');
}
- /**
- * returns expression func object.
- */
- public function it_calls_null(QueryBuilder $qb, Expr $expr)
+ public function it_is_an_expression()
{
- $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\Filter');
}
- public function it_uses_dql_alias_if_passed(QueryBuilder $qb, Expr $expr)
+ public function it_should_return_field()
{
- $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($this->field);
}
}
diff --git a/tests/Filter/LikeSpec.php b/tests/Filter/LikeSpec.php
index f401e5b5..1b734753 100644
--- a/tests/Filter/LikeSpec.php
+++ b/tests/Filter/LikeSpec.php
@@ -1,58 +1,67 @@
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
-namespace tests\Happyr\DoctrineSpecification\Spec;
+namespace tests\Happyr\DoctrineSpecification\Filter;
-use Doctrine\Common\Collections\ArrayCollection;
-use Doctrine\ORM\QueryBuilder;
use Happyr\DoctrineSpecification\Filter\Like;
use PhpSpec\ObjectBehavior;
+/**
+ * @mixin Like
+ */
class LikeSpec extends ObjectBehavior
{
private $field = 'foo';
private $value = 'bar';
+ private $format = Like::CONTAINS;
+
public function let()
{
- $this->beConstructedWith($this->field, $this->value, Like::CONTAINS, 'dqlAlias');
+ $this->beConstructedWith($this->field, $this->value, $this->format);
}
- public function it_is_a_specification()
+ public function it_is_initializable()
{
- $this->shouldHaveType('Happyr\DoctrineSpecification\Specification\Specification');
+ $this->shouldHaveType('Happyr\DoctrineSpecification\Filter\Like');
}
- public function it_surrounds_with_wildcards_when_using_contains(QueryBuilder $qb, ArrayCollection $parameters)
+ public function it_is_a_specification()
{
- $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->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Filter\Filter');
}
- public function it_starts_with_wildcard_when_using_ends_with(QueryBuilder $qb, ArrayCollection $parameters)
+ public function it_should_return_field()
{
- $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->getField()->shouldReturn($this->field);
+ }
- $this->match($qb, null);
+ public function it_should_return_value()
+ {
+ $this->getValue()->shouldReturn($this->value);
}
- public function it_ends_with_wildcard_when_using_starts_with(QueryBuilder $qb, ArrayCollection $parameters)
+ public function it_should_return_format()
{
- $this->beConstructedWith($this->field, $this->value, Like::STARTS_WITH, 'dqlAlias');
- $qb->getParameters()->willReturn($parameters);
- $parameters->count()->willReturn(1);
+ $this->getFormat()->shouldReturn($this->format);
+ }
- $qb->setParameter('comparison_1', 'bar%')->shouldBeCalled();
+ public function it_should_return_format_ends_with()
+ {
+ $this->beConstructedWith($this->field, $this->value, Like::ENDS_WITH);
+ $this->getFormat()->shouldReturn(Like::ENDS_WITH);
+ }
- $this->match($qb, null);
+ public function it_should_return_format_starts_with()
+ {
+ $this->beConstructedWith($this->field, $this->value, Like::STARTS_WITH);
+ $this->getFormat()->shouldReturn(Like::STARTS_WITH);
}
}
diff --git a/tests/Filter/SliceSpec.php b/tests/Filter/SliceSpec.php
deleted file mode 100644
index c0636aad..00000000
--- a/tests/Filter/SliceSpec.php
+++ /dev/null
@@ -1,49 +0,0 @@
-beConstructedWith($this->sliceSize, 0);
- }
-
- public function it_is_a_specification()
- {
- $this->shouldHaveType('Happyr\DoctrineSpecification\Query\QueryModifier');
- }
-
- public function it_slice_with_zero_index(QueryBuilder $qb)
- {
- $this->beConstructedWith($this->sliceSize, 0);
-
- $qb->setMaxResults($this->sliceSize)->shouldBeCalled();
-
- $this->modify($qb, 'a');
- }
-
- public function it_slice_with_second_index(QueryBuilder $qb)
- {
- $sliceNumber = 1;
-
- $this->beConstructedWith($this->sliceSize, $sliceNumber);
-
- $qb->setMaxResults($this->sliceSize)->shouldBeCalled();
- $qb->setFirstResult($this->sliceSize * $sliceNumber)->shouldBeCalled();
-
- $this->modify($qb, 'a');
- }
-}
diff --git a/tests/Logic/LogicXSpec.php b/tests/Logic/LogicXSpec.php
deleted file mode 100644
index 3d4daf34..00000000
--- a/tests/Logic/LogicXSpec.php
+++ /dev/null
@@ -1,66 +0,0 @@
-beConstructedWith(self::EXPRESSION, array($specificationA, $specificationB));
- }
-
- public function it_is_a_specification()
- {
- $this->shouldHaveType('Happyr\DoctrineSpecification\Specification\Specification');
- }
-
- public 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);
- }
-
- public 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);
- }
-
- public 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/tests/Logic/NotSpec.php b/tests/Logic/NotSpec.php
deleted file mode 100644
index 5fb3a0d0..00000000
--- a/tests/Logic/NotSpec.php
+++ /dev/null
@@ -1,54 +0,0 @@
-beConstructedWith($filterExpr, null);
- }
-
- /**
- * calls parent.
- */
- public 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.
- */
- public function it_modifies_parent_query(QueryBuilder $qb, Specification $spec)
- {
- $this->beConstructedWith($spec, null);
-
- $spec->modify($qb, 'a')->shouldBeCalled();
- $this->modify($qb, 'a');
- }
-
- public function it_does_not_modify_parent_query(QueryBuilder $qb)
- {
- $this->modify($qb, 'a');
- }
-}
diff --git a/tests/Query/InnerJoinSpec.php b/tests/Query/InnerJoinSpec.php
deleted file mode 100644
index 3091bf54..00000000
--- a/tests/Query/InnerJoinSpec.php
+++ /dev/null
@@ -1,36 +0,0 @@
-beConstructedWith('user', 'authUser', 'a');
- }
-
- public function it_is_a_specification()
- {
- $this->shouldHaveType('Happyr\DoctrineSpecification\Query\QueryModifier');
- }
-
- public function it_joins_with_default_dql_alias(QueryBuilder $qb)
- {
- $qb->innerJoin('a.user', 'authUser')->shouldBeCalled();
- $this->modify($qb, 'a');
- }
-
- public function it_uses_local_alias_if_global_was_not_set(QueryBuilder $qb)
- {
- $this->beConstructedWith('user', 'authUser');
- $qb->innerJoin('b.user', 'authUser')->shouldBeCalled();
- $this->modify($qb, 'b');
- }
-}
diff --git a/tests/Query/JoinSpec.php b/tests/Query/JoinSpec.php
deleted file mode 100644
index a5114dd8..00000000
--- a/tests/Query/JoinSpec.php
+++ /dev/null
@@ -1,36 +0,0 @@
-beConstructedWith('user', 'authUser', 'a');
- }
-
- public function it_is_a_specification()
- {
- $this->shouldHaveType('Happyr\DoctrineSpecification\Query\QueryModifier');
- }
-
- public function it_joins_with_default_dql_alias(QueryBuilder $qb)
- {
- $qb->join('a.user', 'authUser')->shouldBeCalled();
- $this->modify($qb, 'a');
- }
-
- public function it_uses_local_alias_if_global_was_not_set(QueryBuilder $qb)
- {
- $this->beConstructedWith('user', 'authUser');
- $qb->join('b.user', 'authUser')->shouldBeCalled();
- $this->modify($qb, 'b');
- }
-}
diff --git a/tests/Query/LeftJoinSpec.php b/tests/Query/LeftJoinSpec.php
deleted file mode 100644
index 5b4cb1ba..00000000
--- a/tests/Query/LeftJoinSpec.php
+++ /dev/null
@@ -1,36 +0,0 @@
-beConstructedWith('user', 'authUser', 'a');
- }
-
- public function it_is_a_specification()
- {
- $this->shouldHaveType('Happyr\DoctrineSpecification\Query\QueryModifier');
- }
-
- public function it_joins_with_default_dql_alias(QueryBuilder $qb)
- {
- $qb->leftJoin('a.user', 'authUser')->shouldBeCalled();
- $this->modify($qb, 'a');
- }
-
- public function it_uses_local_alias_if_global_was_not_set(QueryBuilder $qb)
- {
- $this->beConstructedWith('user', 'authUser');
- $qb->leftJoin('b.user', 'authUser')->shouldBeCalled();
- $this->modify($qb, 'b');
- }
-}
diff --git a/tests/QueryModifier/InnerJoinSpec.php b/tests/QueryModifier/InnerJoinSpec.php
new file mode 100644
index 00000000..c0830b67
--- /dev/null
+++ b/tests/QueryModifier/InnerJoinSpec.php
@@ -0,0 +1,73 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace tests\Happyr\DoctrineSpecification\QueryModifier;
+
+use Happyr\DoctrineSpecification\Filter\Filter;
+use Happyr\DoctrineSpecification\QueryModifier\InnerJoin;
+use PhpSpec\ObjectBehavior;
+
+/**
+ * @mixin InnerJoin
+ */
+class InnerJoinSpec extends ObjectBehavior
+{
+ private $field = 'user';
+
+ private $alias = 'authUser';
+
+ public function let()
+ {
+ $this->beConstructedWith($this->field, $this->alias, null, null);
+ }
+
+ public function it_is_initializable()
+ {
+ $this->shouldHaveType('Happyr\DoctrineSpecification\QueryModifier\InnerJoin');
+ }
+
+ public function it_is_a_specification()
+ {
+ $this->shouldHaveType('Happyr\DoctrineSpecification\QueryModifier\QueryModifier');
+ }
+
+ public function it_should_return_field()
+ {
+ $this->getField()->shouldReturn($this->field);
+ }
+
+ public function it_should_return_alias()
+ {
+ $this->getAlias()->shouldReturn($this->alias);
+ }
+
+ public function it_should_return_empty_condition()
+ {
+ $this->getCondition()->shouldReturn(null);
+ }
+
+ public function it_should_return_empty_condition_type()
+ {
+ $this->getConditionType()->shouldReturn(null);
+ }
+
+ public function it_should_on_condition(Filter $condition)
+ {
+ $this->beConstructedWith($this->field, $this->alias, InnerJoin::ON, $condition);
+ $this->getCondition()->shouldReturn($condition);
+ $this->getConditionType()->shouldReturn(InnerJoin::ON);
+ }
+
+ public function it_should_with_condition(Filter $condition)
+ {
+ $this->beConstructedWith($this->field, $this->alias, InnerJoin::WITH, $condition);
+ $this->getCondition()->shouldReturn($condition);
+ $this->getConditionType()->shouldReturn(InnerJoin::WITH);
+ }
+}
diff --git a/tests/QueryModifier/JoinSpec.php b/tests/QueryModifier/JoinSpec.php
new file mode 100644
index 00000000..22e164da
--- /dev/null
+++ b/tests/QueryModifier/JoinSpec.php
@@ -0,0 +1,73 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace tests\Happyr\DoctrineSpecification\QueryModifier;
+
+use Happyr\DoctrineSpecification\Filter\Filter;
+use Happyr\DoctrineSpecification\QueryModifier\Join;
+use PhpSpec\ObjectBehavior;
+
+/**
+ * @mixin Join
+ */
+class JoinSpec extends ObjectBehavior
+{
+ private $field = 'user';
+
+ private $alias = 'authUser';
+
+ public function let()
+ {
+ $this->beConstructedWith($this->field, $this->alias, null, null);
+ }
+
+ public function it_is_initializable()
+ {
+ $this->shouldHaveType('Happyr\DoctrineSpecification\QueryModifier\Join');
+ }
+
+ public function it_is_a_specification()
+ {
+ $this->shouldHaveType('Happyr\DoctrineSpecification\QueryModifier\QueryModifier');
+ }
+
+ public function it_should_return_field()
+ {
+ $this->getField()->shouldReturn($this->field);
+ }
+
+ public function it_should_return_alias()
+ {
+ $this->getAlias()->shouldReturn($this->alias);
+ }
+
+ public function it_should_return_empty_condition()
+ {
+ $this->getCondition()->shouldReturn(null);
+ }
+
+ public function it_should_return_empty_condition_type()
+ {
+ $this->getConditionType()->shouldReturn(null);
+ }
+
+ public function it_should_on_condition(Filter $condition)
+ {
+ $this->beConstructedWith($this->field, $this->alias, Join::ON, $condition);
+ $this->getCondition()->shouldReturn($condition);
+ $this->getConditionType()->shouldReturn(Join::ON);
+ }
+
+ public function it_should_with_condition(Filter $condition)
+ {
+ $this->beConstructedWith($this->field, $this->alias, Join::WITH, $condition);
+ $this->getCondition()->shouldReturn($condition);
+ $this->getConditionType()->shouldReturn(Join::WITH);
+ }
+}
diff --git a/tests/QueryModifier/LeftJoinSpec.php b/tests/QueryModifier/LeftJoinSpec.php
new file mode 100644
index 00000000..a0d84850
--- /dev/null
+++ b/tests/QueryModifier/LeftJoinSpec.php
@@ -0,0 +1,73 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace tests\Happyr\DoctrineSpecification\QueryModifier;
+
+use Happyr\DoctrineSpecification\Filter\Filter;
+use Happyr\DoctrineSpecification\QueryModifier\LeftJoin;
+use PhpSpec\ObjectBehavior;
+
+/**
+ * @mixin LeftJoin
+ */
+class LeftJoinSpec extends ObjectBehavior
+{
+ private $field = 'user';
+
+ private $alias = 'authUser';
+
+ public function let()
+ {
+ $this->beConstructedWith($this->field, $this->alias, null, null);
+ }
+
+ public function it_is_initializable()
+ {
+ $this->shouldHaveType('Happyr\DoctrineSpecification\QueryModifier\LeftJoin');
+ }
+
+ public function it_is_a_specification()
+ {
+ $this->shouldHaveType('Happyr\DoctrineSpecification\QueryModifier\QueryModifier');
+ }
+
+ public function it_should_return_field()
+ {
+ $this->getField()->shouldReturn($this->field);
+ }
+
+ public function it_should_return_alias()
+ {
+ $this->getAlias()->shouldReturn($this->alias);
+ }
+
+ public function it_should_return_empty_condition()
+ {
+ $this->getCondition()->shouldReturn(null);
+ }
+
+ public function it_should_return_empty_condition_type()
+ {
+ $this->getConditionType()->shouldReturn(null);
+ }
+
+ public function it_should_on_condition(Filter $condition)
+ {
+ $this->beConstructedWith($this->field, $this->alias, LeftJoin::ON, $condition);
+ $this->getCondition()->shouldReturn($condition);
+ $this->getConditionType()->shouldReturn(LeftJoin::ON);
+ }
+
+ public function it_should_with_condition(Filter $condition)
+ {
+ $this->beConstructedWith($this->field, $this->alias, LeftJoin::WITH, $condition);
+ $this->getCondition()->shouldReturn($condition);
+ $this->getConditionType()->shouldReturn(LeftJoin::WITH);
+ }
+}
diff --git a/tests/Result/AsArraySpec.php b/tests/Result/AsArraySpec.php
deleted file mode 100644
index e9d3f793..00000000
--- a/tests/Result/AsArraySpec.php
+++ /dev/null
@@ -1,26 +0,0 @@
-shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Result\ResultModifier');
- }
-
- public function it_sets_hydration_mode_to_array(AbstractQuery $query)
- {
- $query->setHydrationMode(Query::HYDRATE_ARRAY)->shouldBeCalled();
-
- $this->modify($query);
- }
-}
diff --git a/tests/Result/AsSingleScalarSpec.php b/tests/Result/AsSingleScalarSpec.php
deleted file mode 100644
index 149e0bef..00000000
--- a/tests/Result/AsSingleScalarSpec.php
+++ /dev/null
@@ -1,26 +0,0 @@
-shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Result\ResultModifier');
- }
-
- public function it_sets_hydration_mode_to_object(AbstractQuery $query)
- {
- $query->setHydrationMode(Query::HYDRATE_SINGLE_SCALAR)->shouldBeCalled();
-
- $this->modify($query);
- }
-}
diff --git a/tests/Result/CacheSpec.php b/tests/Result/CacheSpec.php
deleted file mode 100644
index 454daed4..00000000
--- a/tests/Result/CacheSpec.php
+++ /dev/null
@@ -1,32 +0,0 @@
-beConstructedWith($this->lifetime);
- }
-
- public function it_is_a_specification()
- {
- $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Result\ResultModifier');
- }
-
- public function it_caches_query_for_given_time(AbstractQuery $query)
- {
- $query->setResultCacheLifetime($this->lifetime)->shouldBeCalled();
-
- $this->modify($query);
- }
-}
diff --git a/tests/Result/RoundDateTimeSpec.php b/tests/Result/RoundDateTimeSpec.php
deleted file mode 100644
index 1f833c94..00000000
--- a/tests/Result/RoundDateTimeSpec.php
+++ /dev/null
@@ -1,47 +0,0 @@
-beConstructedWith($this->roundSeconds);
- }
-
- public function it_is_a_specification()
- {
- $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Result\RoundDateTime');
- }
-
- public function it_round_date_time_in_query_parameters_for_given_time(
- AbstractQuery $query,
- Parameter $scalarParam,
- Parameter $datetimeParam
- ) {
- $name = 'now';
- $type = 'datetime';
- $date = new \DateTime('15:55:34');
-
- $scalarParam->getValue()->willReturn('foo');
-
- $datetimeParam->getValue()->willReturn($date);
- $datetimeParam->getName()->willReturn($name);
- $datetimeParam->getType()->willReturn($type);
-
- $query->getParameters()->willReturn(new ArrayCollection([$scalarParam, $datetimeParam]));
- $query->setParameter($name, new \DateTime('15:00:00'), $type)->shouldBeCalled();
-
- $this->modify($query);
- }
-}
diff --git a/tests/ResultManagement/SliceSpec.php b/tests/ResultManagement/SliceSpec.php
new file mode 100644
index 00000000..95c1d53f
--- /dev/null
+++ b/tests/ResultManagement/SliceSpec.php
@@ -0,0 +1,39 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace tests\Happyr\DoctrineSpecification\ResultManagement;
+
+use Happyr\DoctrineSpecification\ResultManagement\Slice;
+use PhpSpec\ObjectBehavior;
+
+/**
+ * @mixin Slice
+ */
+class SliceSpec extends ObjectBehavior
+{
+ /**
+ * @var int
+ */
+ private $sliceSize = 25;
+
+ public function let()
+ {
+ $this->beConstructedWith($this->sliceSize, 0);
+ }
+
+ public function it_is_initializable()
+ {
+ $this->shouldHaveType('Happyr\DoctrineSpecification\ResultManagement\Slice');
+ }
+
+ public function it_is_a_specification()
+ {
+ $this->shouldHaveType('Happyr\DoctrineSpecification\Specification');
+ }
+}
diff --git a/tests/ResultModifier/AsArraySpec.php b/tests/ResultModifier/AsArraySpec.php
new file mode 100644
index 00000000..c58a7d0f
--- /dev/null
+++ b/tests/ResultModifier/AsArraySpec.php
@@ -0,0 +1,29 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace tests\Happyr\DoctrineSpecification\ResultModifier;
+
+use Happyr\DoctrineSpecification\ResultModifier\AsArray;
+use PhpSpec\ObjectBehavior;
+
+/**
+ * @mixin AsArray
+ */
+class AsArraySpec extends ObjectBehavior
+{
+ public function it_is_initializable()
+ {
+ $this->shouldHaveType('Happyr\DoctrineSpecification\ResultModifier\AsArray');
+ }
+
+ public function it_is_a_result_modifier()
+ {
+ $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\ResultModifier\ResultModifier');
+ }
+}
diff --git a/tests/ResultModifier/AsSingleScalarSpec.php b/tests/ResultModifier/AsSingleScalarSpec.php
new file mode 100644
index 00000000..767416ff
--- /dev/null
+++ b/tests/ResultModifier/AsSingleScalarSpec.php
@@ -0,0 +1,29 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace tests\Happyr\DoctrineSpecification\ResultModifier;
+
+use Happyr\DoctrineSpecification\ResultModifier\AsSingleScalar;
+use PhpSpec\ObjectBehavior;
+
+/**
+ * @mixin AsSingleScalar
+ */
+class AsSingleScalarSpec extends ObjectBehavior
+{
+ public function it_is_initializable()
+ {
+ $this->shouldHaveType('Happyr\DoctrineSpecification\ResultModifier\AsSingleScalar');
+ }
+
+ public function it_is_a_result_modifier()
+ {
+ $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\ResultModifier\ResultModifier');
+ }
+}
diff --git a/tests/ResultModifier/CacheSpec.php b/tests/ResultModifier/CacheSpec.php
new file mode 100644
index 00000000..a6215e26
--- /dev/null
+++ b/tests/ResultModifier/CacheSpec.php
@@ -0,0 +1,41 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace tests\Happyr\DoctrineSpecification\ResultModifier;
+
+use Happyr\DoctrineSpecification\ResultModifier\Cache;
+use PhpSpec\ObjectBehavior;
+
+/**
+ * @mixin Cache
+ */
+class CacheSpec extends ObjectBehavior
+{
+ private $lifetime = 3600;
+
+ public function let()
+ {
+ $this->beConstructedWith($this->lifetime);
+ }
+
+ public function it_is_initializable()
+ {
+ $this->shouldHaveType('Happyr\DoctrineSpecification\ResultModifier\Cache');
+ }
+
+ public function it_is_a_specification()
+ {
+ $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\ResultModifier\ResultModifier');
+ }
+
+ public function it_should_return_field()
+ {
+ $this->getCacheLifetime()->shouldReturn($this->lifetime);
+ }
+}
diff --git a/tests/ResultModifier/RoundDateTimeSpec.php b/tests/ResultModifier/RoundDateTimeSpec.php
new file mode 100644
index 00000000..85bf70d5
--- /dev/null
+++ b/tests/ResultModifier/RoundDateTimeSpec.php
@@ -0,0 +1,35 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace tests\Happyr\DoctrineSpecification\ResultModifier;
+
+use Happyr\DoctrineSpecification\ResultModifier\RoundDateTime;
+
+/**
+ * @mixin RoundDateTime
+ */
+class RoundDateTimeSpec
+{
+ private $roundSeconds = 3600;
+
+ public function let()
+ {
+ $this->beConstructedWith($this->roundSeconds);
+ }
+
+ public function it_is_initializable()
+ {
+ $this->shouldHaveType('Happyr\DoctrineSpecification\ResultModifier\RoundDateTime');
+ }
+
+ public function it_is_a_specification()
+ {
+ $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Result\RoundDateTime');
+ }
+}
diff --git a/tests/SpecSpec.php b/tests/SpecSpec.php
deleted file mode 100644
index 4e8cae26..00000000
--- a/tests/SpecSpec.php
+++ /dev/null
@@ -1,17 +0,0 @@
-andX()->shouldReturnAnInstanceOf('Happyr\DoctrineSpecification\Logic\LogicX');
- }
-}
diff --git a/tests/Transformer/Doctrine/ORM/Query/QueryTransformerCollectionSpec.php b/tests/Transformer/Doctrine/ORM/Query/QueryTransformerCollectionSpec.php
new file mode 100644
index 00000000..c2103f8e
--- /dev/null
+++ b/tests/Transformer/Doctrine/ORM/Query/QueryTransformerCollectionSpec.php
@@ -0,0 +1,56 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace tests\Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Query;
+
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Query\QueryTransformerCollection;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Query\ResultModifier\AsArrayTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Query\ResultModifier\AsSingleScalarTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Query\ResultModifier\CacheTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Query\ResultModifier\RoundDateTimeTransformer;
+use PhpSpec\ObjectBehavior;
+
+/**
+ * @mixin QueryTransformerCollection
+ */
+class QueryTransformerCollectionSpec extends ObjectBehavior
+{
+ public function let()
+ {
+ $this->beConstructedWith([]);
+ }
+
+ public function it_is_initializable()
+ {
+ $this->shouldHaveType('Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Query\QueryTransformerCollection');
+ }
+
+ public function it_is_a_specification()
+ {
+ $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\Query\QueryTransformer');
+ }
+
+ public function it_should_available_set_transformer()
+ {
+ $this->beConstructedWith([
+ new AsArrayTransformer(),
+ new AsSingleScalarTransformer(),
+ new CacheTransformer(),
+ new RoundDateTimeTransformer(),
+ ]);
+ }
+
+ public function it_should_available_add_transformers()
+ {
+ $this->addTransformer(new AsArrayTransformer());
+ $this->addTransformer(new AsSingleScalarTransformer());
+ $this->addTransformer(new CacheTransformer());
+ $this->addTransformer(new RoundDateTimeTransformer());
+ }
+}
diff --git a/tests/Transformer/Doctrine/ORM/QueryBuilder/QueryBuilderTransformerCollectionSpec.php b/tests/Transformer/Doctrine/ORM/QueryBuilder/QueryBuilderTransformerCollectionSpec.php
new file mode 100644
index 00000000..5428af05
--- /dev/null
+++ b/tests/Transformer/Doctrine/ORM/QueryBuilder/QueryBuilderTransformerCollectionSpec.php
@@ -0,0 +1,119 @@
+
+ * @copyright Copyright (c) 2014, Tobias Nyholm
+ * @license http://opensource.org/licenses/MIT
+ */
+
+namespace tests\Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder;
+
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter\EqualsTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter\GreaterOrEqualThanTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter\GreaterThanTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter\InstanceOfXTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter\InTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter\IsNotNullTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter\IsNullTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter\LessOrEqualThanTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter\LessThanTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter\LikeTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter\Logic\AndXTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter\Logic\NotTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter\Logic\OrXTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\Filter\NotEqualsTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformerCollection;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryModifier\GroupByTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryModifier\HavingTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryModifier\InnerJoinTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryModifier\JoinTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryModifier\LeftJoinTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryModifier\QueryModifierCollectionTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\ResultManagement\CountOfTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\ResultManagement\LimitTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\ResultManagement\OffsetTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\ResultManagement\OrderByTransformer;
+use Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\ResultManagement\SliceTransformer;
+use PhpSpec\ObjectBehavior;
+
+/**
+ * @mixin QueryBuilderTransformerCollection
+ */
+class QueryBuilderTransformerCollectionSpec extends ObjectBehavior
+{
+ public function let()
+ {
+ $this->beConstructedWith([]);
+ }
+
+ public function it_is_initializable()
+ {
+ $this->shouldHaveType('Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformerCollection');
+ }
+
+ public function it_is_a_specification()
+ {
+ $this->shouldBeAnInstanceOf('Happyr\DoctrineSpecification\Transformer\Doctrine\ORM\QueryBuilder\QueryBuilderTransformer');
+ }
+
+ public function it_should_available_set_transformer()
+ {
+ $this->beConstructedWith([
+ new EqualsTransformer(),
+ new GreaterOrEqualThanTransformer(),
+ new GreaterThanTransformer(),
+ new InstanceOfXTransformer(),
+ new InTransformer(),
+ new IsNotNullTransformer(),
+ new IsNullTransformer(),
+ new LessOrEqualThanTransformer(),
+ new LessThanTransformer(),
+ new LikeTransformer(),
+ new NotEqualsTransformer(),
+ new AndXTransformer(),
+ new NotTransformer(),
+ new OrXTransformer(),
+ new GroupByTransformer(),
+ new HavingTransformer(),
+ new InnerJoinTransformer(),
+ new JoinTransformer(),
+ new LeftJoinTransformer(),
+ new QueryModifierCollectionTransformer(),
+ new CountOfTransformer(),
+ new LimitTransformer(),
+ new OffsetTransformer(),
+ new OrderByTransformer(),
+ new SliceTransformer(),
+ ]);
+ }
+
+ public function it_should_available_add_transformers()
+ {
+ $this->addTransformer(new EqualsTransformer());
+ $this->addTransformer(new GreaterOrEqualThanTransformer());
+ $this->addTransformer(new GreaterThanTransformer());
+ $this->addTransformer(new InstanceOfXTransformer());
+ $this->addTransformer(new InTransformer());
+ $this->addTransformer(new IsNotNullTransformer());
+ $this->addTransformer(new IsNullTransformer());
+ $this->addTransformer(new LessOrEqualThanTransformer());
+ $this->addTransformer(new LessThanTransformer());
+ $this->addTransformer(new LikeTransformer());
+ $this->addTransformer(new NotEqualsTransformer());
+ $this->addTransformer(new AndXTransformer());
+ $this->addTransformer(new NotTransformer());
+ $this->addTransformer(new OrXTransformer());
+ $this->addTransformer(new GroupByTransformer());
+ $this->addTransformer(new HavingTransformer());
+ $this->addTransformer(new InnerJoinTransformer());
+ $this->addTransformer(new JoinTransformer());
+ $this->addTransformer(new LeftJoinTransformer());
+ $this->addTransformer(new QueryModifierCollectionTransformer());
+ $this->addTransformer(new CountOfTransformer());
+ $this->addTransformer(new LimitTransformer());
+ $this->addTransformer(new OffsetTransformer());
+ $this->addTransformer(new OrderByTransformer());
+ $this->addTransformer(new SliceTransformer());
+ }
+}