2 /***************************************************************
5 * (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
8 * This class is a backport of the corresponding class of FLOW3.
9 * All credits go to the v5 team.
11 * This script is part of the TYPO3 project. The TYPO3 project is
12 * free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * The GNU General Public License can be found at
18 * http://www.gnu.org/copyleft/gpl.html.
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
29 * The Query class used to run queries against the database
32 * @subpackage Persistence
37 class Tx_Extbase_Persistence_Query
implements Tx_Extbase_Persistence_QueryInterface
{
45 * @var Tx_Extbase_Persistence_DataMapper
47 protected $dataMapper;
50 * @var Tx_Extbase_Persistence_Manager
52 protected $persistenceManager;
55 * @var Tx_Extbase_Persistence_QOM_QueryObjectModelFactoryInterface
57 protected $qomFactory;
60 * @var Tx_Extbase_Persistence_QOM_SourceInterface
65 * @var Tx_Extbase_Persistence_QOM_ConstraintInterface
67 protected $constraint;
70 * @var Tx_Extbase_Persistence_QOM_Statement
77 protected $orderings = array();
92 * @var Tx_Extbase_Persistence_QuerySettingsInterface
94 protected $querySettings;
97 * Constructs a query object working on the given class name
101 public function __construct($type) {
106 * Injects the persistence manager, used to fetch the CR session
108 * @param Tx_Extbase_Persistence_ManagerInterface $persistenceManager
111 public function injectPersistenceManager(Tx_Extbase_Persistence_ManagerInterface
$persistenceManager) {
112 $this->persistenceManager
= $persistenceManager;
113 $this->qomFactory
= $this->persistenceManager
->getBackend()->getQomFactory();
117 * Injects the DataMapper to map nodes to objects
119 * @param Tx_Extbase_Persistence_Mapper_DataMapper $dataMapper
122 public function injectDataMapper(Tx_Extbase_Persistence_Mapper_DataMapper
$dataMapper) {
123 $this->dataMapper
= $dataMapper;
127 * Sets the Query Settings. These Query settings must match the settings expected by
128 * the specific Storage Backend.
130 * @param Tx_Extbase_Persistence_QuerySettingsInterface $querySettings The Query Settings
132 * @api This method is not part of FLOW3 API
134 public function setQuerySettings(Tx_Extbase_Persistence_QuerySettingsInterface
$querySettings) {
135 $this->querySettings
= $querySettings;
139 * Returns the Query Settings.
141 * @return Tx_Extbase_Persistence_QuerySettingsInterface $querySettings The Query Settings
142 * @api This method is not part of FLOW3 API
144 public function getQuerySettings() {
145 if (!($this->querySettings
instanceof Tx_Extbase_Persistence_QuerySettingsInterface
)) throw new Tx_Extbase_Persistence_Exception('Tried to get the query settings without seting them before.', 1248689115);
146 return $this->querySettings
;
150 * Returns the type this query cares for.
155 public function getType() {
160 * Sets the source to fetch the result from
162 * @param Tx_Extbase_Persistence_QOM_SourceInterface $source
164 public function setSource(Tx_Extbase_Persistence_QOM_SourceInterface
$source) {
165 $this->source
= $source;
169 * Returns the selectorn name or an empty string, if the source is not a selector
170 * // TODO This has to be checked at another place
171 * @return string The selector name
173 protected function getSelectorName() {
174 if ($this->getSource() instanceof Tx_Extbase_Persistence_QOM_SelectorInterface
) {
175 return $this->source
->getSelectorName();
182 * Gets the node-tuple source for this query.
184 * @return Tx_Extbase_Persistence_QOM_SourceInterface the node-tuple source; non-null
186 public function getSource() {
187 if ($this->source
=== NULL) {
188 $this->source
= $this->qomFactory
->selector($this->getType(), $this->dataMapper
->convertClassNameToTableName($this->getType()));
190 return $this->source
;
194 * Executes the query against the database and returns the result
196 * @return array<object> The query result as an array of objects
199 public function execute() {
200 $rows = $this->persistenceManager
->getObjectDataByQuery($this);
201 if ($this->getQuerySettings()->getReturnRawQueryResult() === TRUE) {
204 return $this->dataMapper
->map($this->getType(), $rows);
209 * Executes the number of matching objects for the query
211 * @return integer The number of matching objects
214 public function count() {
215 return $this->persistenceManager
->getObjectCountByQuery($this);
219 * Sets the property names to order the result by. Expected like this:
221 * 'foo' => Tx_Extbase_Persistence_QueryInterface::ORDER_ASCENDING,
222 * 'bar' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING
224 * where 'foo' and 'bar' are property names.
226 * @param array $orderings The property names to order by
227 * @return Tx_Extbase_Persistence_QueryInterface
230 public function setOrderings(array $orderings) {
231 $this->orderings
= $orderings;
236 * Returns the property names to order the result by. Like this:
238 * 'foo' => Tx_Extbase_Persistence_QueryInterface::ORDER_ASCENDING,
239 * 'bar' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING
245 public function getOrderings() {
246 return $this->orderings
;
250 * Sets the maximum size of the result set to limit. Returns $this to allow
251 * for chaining (fluid interface)
253 * @param integer $limit
254 * @return Tx_Extbase_Persistence_QueryInterface
257 public function setLimit($limit) {
258 if (!is_int($limit) ||
$limit < 1) throw new InvalidArgumentException('The limit must be an integer >= 1', 1245071870);
259 $this->limit
= $limit;
264 * Returns the maximum size of the result set to limit.
269 public function getLimit() {
274 * Sets the start offset of the result set to offset. Returns $this to
275 * allow for chaining (fluid interface)
277 * @param integer $offset
278 * @return Tx_Extbase_Persistence_QueryInterface
281 public function setOffset($offset) {
282 if (!is_int($offset) ||
$offset < 0) throw new InvalidArgumentException('The offset must be a positive integer', 1245071872);
283 $this->offset
= $offset;
288 * Returns the start offset of the result set.
293 public function getOffset() {
294 return $this->offset
;
298 * The constraint used to limit the result set. Returns $this to allow
299 * for chaining (fluid interface)
301 * @param Tx_Extbase_Persistence_QOM_ConstraintInterface $constraint
302 * @return Tx_Extbase_Persistence_QueryInterface
305 public function matching($constraint) {
306 $this->constraint
= $constraint;
311 * Sets the statement of this query programmatically. If you use this, you will lose the abstraction from a concrete storage
312 * backend (database).
314 * @param string $statement The statement
315 * @param array $paramerters An array of parameters. These will be bound to placeholders '?' in the $statement.
316 * @return Tx_Extbase_Persistence_QueryInterface
318 public function statement($statement, array $parameters = array()) {
319 $this->statement
= $this->qomFactory
->statement($statement, $parameters);
324 * Returns the statement of this query.
326 * @return Tx_Extbase_Persistence_QOM_Statement
328 public function getStatement() {
329 return $this->statement
;
333 * Gets the constraint for this query.
335 * @return Tx_Extbase_Persistence_QOM_Constraint the constraint, or null if none
336 * @author Karsten Dambekalns <karsten@typo3.org>
339 public function getConstraint() {
340 return $this->constraint
;
344 * Performs a logical conjunction of the given constraints.
346 * @param object $constraint1 First constraint
347 * @param object $constraint2 Second constraint
348 * @return Tx_Extbase_Persistence_QOM_AndInterface
349 * @api Passing more than two constraints as arguments is currently not yet conform to the api of FLOW3
351 public function logicalAnd($constraint1, $constraint2) {
352 $constraints = func_get_args();
353 $numberOfConstraints = func_num_args();
354 if (func_num_args() > 1) {
355 $resultingConstraint = array_shift($constraints);
356 foreach ($constraints as $constraint) {
357 $resultingConstraint = $this->qomFactory
->_and(
358 $resultingConstraint,
363 throw new Tx_Extbase_Persistence_Exception_InvalidNumberOfConstraints('There must be at least two constraints. Got only ' . func_num_args() . '.', 1268056288);
365 return $resultingConstraint;
369 * Performs a logical conjunction of the given constraints.
371 * @param array $constraints An array of constraints
372 * @return Tx_Extbase_Persistence_QOM_AndInterface
374 public function implodeAnd(array $constraints) {
375 $numberOfConstraints = count($constraints);
376 $resultingConstraint = NULL;
377 if ($numberOfConstraints === 1) {
378 return array_shift($constraints);
379 } elseif ($numberOfConstraints > 1) {
380 $resultingConstraint = array_shift($constraints);
381 foreach ($constraints as $constraint) {
382 $resultingConstraint = $this->qomFactory
->_and(
383 $resultingConstraint,
388 return $resultingConstraint;
392 * Performs a logical disjunction of the two given constraints
394 * @param object $constraint1 First constraint
395 * @param object $constraint2 Second constraint
396 * @return Tx_Extbase_Persistence_QOM_OrInterface
397 * @api Passing more than two constraints as arguments is currently not yet conform to the api of FLOW3
399 public function logicalOr($constraint1, $constraint2) {
400 $constraints = func_get_args();
401 $numberOfConstraints = func_num_args();
402 if (func_num_args() > 1) {
403 $resultingConstraint = array_shift($constraints);
404 foreach ($constraints as $constraint) {
405 $resultingConstraint = $this->qomFactory
->_or(
406 $resultingConstraint,
411 throw new Tx_Extbase_Persistence_Exception_InvalidNumberOfConstraints('There must be at least two constraints. Got only ' . func_num_args() . '.', 1268056288);
413 return $resultingConstraint;
417 * Performs a logical conjunction of the given constraints.
419 * @param array $constraints An array of constraints
420 * @return Tx_Extbase_Persistence_QOM_AndInterface
422 public function implodeOr(array $constraints) {
423 $numberOfConstraints = count($constraints);
424 $resultingConstraint = NULL;
425 if ($numberOfConstraints === 1) {
426 return array_shift($constraints);
427 } elseif ($numberOfConstraints > 1) {
428 $resultingConstraint = array_shift($constraints);
429 foreach ($constraints as $constraint) {
430 $resultingConstraint = $this->qomFactory
->_or(
431 $resultingConstraint,
436 return $resultingConstraint;
440 * Performs a logical negation of the given constraint
442 * @param object $constraint Constraint to negate
443 * @return Tx_Extbase_Persistence_QOM_NotInterface
446 public function logicalNot($constraint) {
447 return $this->qomFactory
->not($constraint);
451 * Matches against the (internal) uid.
453 * @param int $uid The uid to match against
454 * @return Tx_Extbase_Persistence_QOM_ComparisonInterface
455 * @deprecated since Extbase 2.0; was removed in FLOW3; will be removed in Extbase 3.0; use equals() ínstead
457 public function withUid($operand) {
458 t3lib_div
::logDeprecatedFunction();
459 return $this->qomFactory
->comparison(
460 $this->qomFactory
->propertyValue('uid', $this->getSelectorName()),
461 Tx_Extbase_Persistence_QueryInterface
::OPERATOR_EQUAL_TO
,
467 * Returns an equals criterion used for matching objects against a query
469 * @param string $propertyName The name of the property to compare against
470 * @param mixed $operand The value to compare with
471 * @param boolean $caseSensitive Whether the equality test should be done case-sensitive
472 * @return Tx_Extbase_Persistence_QOM_ComparisonInterface
475 public function equals($propertyName, $operand, $caseSensitive = TRUE) {
476 if (is_object($operand) ||
$caseSensitive) {
477 $comparison = $this->qomFactory
->comparison(
478 $this->qomFactory
->propertyValue($propertyName, $this->getSelectorName()),
479 Tx_Extbase_Persistence_QueryInterface
::OPERATOR_EQUAL_TO
,
483 $comparison = $this->qomFactory
->comparison(
484 $this->qomFactory
->lowerCase(
485 $this->qomFactory
->propertyValue($propertyName, $this->getSelectorName())
487 Tx_Extbase_Persistence_QueryInterface
::OPERATOR_EQUAL_TO
,
496 * Returns a like criterion used for matching objects against a query
498 * @param string $propertyName The name of the property to compare against
499 * @param mixed $operand The value to compare with
500 * @return Tx_Extbase_Persistence_QOM_ComparisonInterface
503 public function like($propertyName, $operand) {
504 return $this->qomFactory
->comparison(
505 $this->qomFactory
->propertyValue($propertyName, $this->getSelectorName()),
506 Tx_Extbase_Persistence_QueryInterface
::OPERATOR_LIKE
,
512 * Returns a "contains" criterion used for matching objects against a query.
513 * It matches if the multivalued property contains the given operand.
515 * @param string $propertyName The name of the (multivalued) property to compare against
516 * @param mixed $operand The value to compare with
517 * @return Tx_Extbase_Persistence_QOM_ComparisonInterface
520 public function contains($propertyName, $operand){
521 return $this->qomFactory
->comparison(
522 $this->qomFactory
->propertyValue($propertyName, $this->getSelectorName()),
523 Tx_Extbase_Persistence_QueryInterface
::OPERATOR_CONTAINS
,
529 * Returns an "in" criterion used for matching objects against a query. It
530 * matches if the property's value is contained in the multivalued operand.
532 * @param string $propertyName The name of the property to compare against
533 * @param mixed $operand The value to compare with, multivalued
534 * @return Tx_Extbase_Persistence_QOM_ComparisonInterface
537 public function in($propertyName, $operand) {
538 if (!is_array($operand) && (!$operand instanceof ArrayAccess
) && (!$operand instanceof Traversable
)) {
539 throw new Tx_Extbase_Persistence_Exception_UnexpectedTypeException('The "in" operator must be given a mutlivalued operand (array, ArrayAccess, Traversable).', 1264678095);
542 return $this->qomFactory
->comparison(
543 $this->qomFactory
->propertyValue($propertyName, $this->getSelectorName()),
544 Tx_Extbase_Persistence_QueryInterface
::OPERATOR_IN
,
550 * Returns a less than criterion used for matching objects against a query
552 * @param string $propertyName The name of the property to compare against
553 * @param mixed $operand The value to compare with
554 * @return Tx_Extbase_Persistence_QOM_ComparisonInterface
557 public function lessThan($propertyName, $operand) {
558 return $this->qomFactory
->comparison(
559 $this->qomFactory
->propertyValue($propertyName, $this->getSelectorName()),
560 Tx_Extbase_Persistence_QueryInterface
::OPERATOR_LESS_THAN
,
566 * Returns a less or equal than criterion used for matching objects against a query
568 * @param string $propertyName The name of the property to compare against
569 * @param mixed $operand The value to compare with
570 * @return Tx_Extbase_Persistence_QOM_ComparisonInterface
573 public function lessThanOrEqual($propertyName, $operand) {
574 return $this->qomFactory
->comparison(
575 $this->qomFactory
->propertyValue($propertyName, $this->getSelectorName()),
576 Tx_Extbase_Persistence_QueryInterface
::OPERATOR_LESS_THAN_OR_EQUAL_TO
,
582 * Returns a greater than criterion used for matching objects against a query
584 * @param string $propertyName The name of the property to compare against
585 * @param mixed $operand The value to compare with
586 * @return Tx_Extbase_Persistence_QOM_ComparisonInterface
589 public function greaterThan($propertyName, $operand) {
590 return $this->qomFactory
->comparison(
591 $this->qomFactory
->propertyValue($propertyName, $this->getSelectorName()),
592 Tx_Extbase_Persistence_QueryInterface
::OPERATOR_GREATER_THAN
,
598 * Returns a greater than or equal criterion used for matching objects against a query
600 * @param string $propertyName The name of the property to compare against
601 * @param mixed $operand The value to compare with
602 * @return Tx_Extbase_Persistence_QOM_ComparisonInterface
605 public function greaterThanOrEqual($propertyName, $operand) {
606 return $this->qomFactory
->comparison(
607 $this->qomFactory
->propertyValue($propertyName, $this->getSelectorName()),
608 Tx_Extbase_Persistence_QueryInterface
::OPERATOR_GREATER_THAN_OR_EQUAL_TO
,