c294db3c48a3fcbb023f6d7ef00ac84f0076b8db
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Persistence / Query.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
6 * All rights reserved
7 *
8 * This class is a backport of the corresponding class of FLOW3.
9 * All credits go to the v5 team.
10 *
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.
16 *
17 * The GNU General Public License can be found at
18 * http://www.gnu.org/copyleft/gpl.html.
19 *
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.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27
28 /**
29 * The Query class used to run queries against the database
30 *
31 * @package Extbase
32 * @subpackage Persistence
33 * @version $Id$
34 * @scope prototype
35 * @api
36 */
37 class Tx_Extbase_Persistence_Query implements Tx_Extbase_Persistence_QueryInterface {
38
39 /**
40 * @var string
41 */
42 protected $type;
43
44 /**
45 * @var Tx_Extbase_Persistence_DataMapper
46 */
47 protected $dataMapper;
48
49 /**
50 * @var Tx_Extbase_Persistence_Manager
51 */
52 protected $persistenceManager;
53
54 /**
55 * @var Tx_Extbase_Persistence_QOM_QueryObjectModelFactoryInterface
56 */
57 protected $qomFactory;
58
59 /**
60 * @var Tx_Extbase_Persistence_QOM_SourceInterface
61 */
62 protected $source;
63
64 /**
65 * @var Tx_Extbase_Persistence_QOM_ConstraintInterface
66 */
67 protected $constraint;
68
69 /**
70 * @var Tx_Extbase_Persistence_QOM_Statement
71 */
72 protected $statement;
73
74 /**
75 * @var int
76 */
77 protected $orderings = array();
78
79 /**
80 * @var int
81 */
82 protected $limit;
83
84 /**
85 * @var int
86 */
87 protected $offset;
88
89 /**
90 * The query settings.
91 *
92 * @var Tx_Extbase_Persistence_QuerySettingsInterface
93 */
94 protected $querySettings;
95
96 /**
97 * Constructs a query object working on the given class name
98 *
99 * @param string $type
100 */
101 public function __construct($type) {
102 $this->type = $type;
103 }
104
105 /**
106 * Injects the persistence manager, used to fetch the CR session
107 *
108 * @param Tx_Extbase_Persistence_ManagerInterface $persistenceManager
109 * @return void
110 */
111 public function injectPersistenceManager(Tx_Extbase_Persistence_ManagerInterface $persistenceManager) {
112 $this->persistenceManager = $persistenceManager;
113 $this->qomFactory = $this->persistenceManager->getBackend()->getQomFactory();
114 }
115
116 /**
117 * Injects the DataMapper to map nodes to objects
118 *
119 * @param Tx_Extbase_Persistence_Mapper_DataMapper $dataMapper
120 * @return void
121 */
122 public function injectDataMapper(Tx_Extbase_Persistence_Mapper_DataMapper $dataMapper) {
123 $this->dataMapper = $dataMapper;
124 }
125
126 /**
127 * Sets the Query Settings. These Query settings must match the settings expected by
128 * the specific Storage Backend.
129 *
130 * @param Tx_Extbase_Persistence_QuerySettingsInterface $querySettings The Query Settings
131 * @return void
132 * @api This method is not part of FLOW3 API
133 */
134 public function setQuerySettings(Tx_Extbase_Persistence_QuerySettingsInterface $querySettings) {
135 $this->querySettings = $querySettings;
136 }
137
138 /**
139 * Returns the Query Settings.
140 *
141 * @return Tx_Extbase_Persistence_QuerySettingsInterface $querySettings The Query Settings
142 * @api This method is not part of FLOW3 API
143 */
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;
147 }
148
149 /**
150 * Returns the type this query cares for.
151 *
152 * @return string
153 * @api
154 */
155 public function getType() {
156 return $this->type;
157 }
158
159 /**
160 * Sets the source to fetch the result from
161 *
162 * @param Tx_Extbase_Persistence_QOM_SourceInterface $source
163 */
164 public function setSource(Tx_Extbase_Persistence_QOM_SourceInterface $source) {
165 $this->source = $source;
166 }
167
168 /**
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
172 */
173 protected function getSelectorName() {
174 if ($this->getSource() instanceof Tx_Extbase_Persistence_QOM_SelectorInterface) {
175 return $this->source->getSelectorName();
176 } else {
177 return '';
178 }
179 }
180
181 /**
182 * Gets the node-tuple source for this query.
183 *
184 * @return Tx_Extbase_Persistence_QOM_SourceInterface the node-tuple source; non-null
185 */
186 public function getSource() {
187 if ($this->source === NULL) {
188 $this->source = $this->qomFactory->selector($this->getType(), $this->dataMapper->convertClassNameToTableName($this->getType()));
189 }
190 return $this->source;
191 }
192
193 /**
194 * Executes the query against the database and returns the result
195 *
196 * @return array<object> The query result as an array of objects
197 * @api
198 */
199 public function execute() {
200 $rows = $this->persistenceManager->getObjectDataByQuery($this);
201 if ($this->getQuerySettings()->getReturnRawQueryResult() === TRUE) {
202 return $rows;
203 } else {
204 return $this->dataMapper->map($this->getType(), $rows);
205 }
206 }
207
208 /**
209 * Executes the number of matching objects for the query
210 *
211 * @return integer The number of matching objects
212 * @api
213 */
214 public function count() {
215 return $this->persistenceManager->getObjectCountByQuery($this);
216 }
217
218 /**
219 * Sets the property names to order the result by. Expected like this:
220 * array(
221 * 'foo' => Tx_Extbase_Persistence_QueryInterface::ORDER_ASCENDING,
222 * 'bar' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING
223 * )
224 * where 'foo' and 'bar' are property names.
225 *
226 * @param array $orderings The property names to order by
227 * @return Tx_Extbase_Persistence_QueryInterface
228 * @api
229 */
230 public function setOrderings(array $orderings) {
231 $this->orderings = $orderings;
232 return $this;
233 }
234
235 /**
236 * Returns the property names to order the result by. Like this:
237 * array(
238 * 'foo' => Tx_Extbase_Persistence_QueryInterface::ORDER_ASCENDING,
239 * 'bar' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING
240 * )
241 *
242 * @return array
243 * @api
244 */
245 public function getOrderings() {
246 return $this->orderings;
247 }
248
249 /**
250 * Sets the maximum size of the result set to limit. Returns $this to allow
251 * for chaining (fluid interface)
252 *
253 * @param integer $limit
254 * @return Tx_Extbase_Persistence_QueryInterface
255 * @api
256 */
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;
260 return $this;
261 }
262
263 /**
264 * Returns the maximum size of the result set to limit.
265 *
266 * @param integer
267 * @api
268 */
269 public function getLimit() {
270 return $this->limit;
271 }
272
273 /**
274 * Sets the start offset of the result set to offset. Returns $this to
275 * allow for chaining (fluid interface)
276 *
277 * @param integer $offset
278 * @return Tx_Extbase_Persistence_QueryInterface
279 * @api
280 */
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;
284 return $this;
285 }
286
287 /**
288 * Returns the start offset of the result set.
289 *
290 * @return integer
291 * @api
292 */
293 public function getOffset() {
294 return $this->offset;
295 }
296
297 /**
298 * The constraint used to limit the result set. Returns $this to allow
299 * for chaining (fluid interface)
300 *
301 * @param Tx_Extbase_Persistence_QOM_ConstraintInterface $constraint
302 * @return Tx_Extbase_Persistence_QueryInterface
303 * @api
304 */
305 public function matching($constraint) {
306 $this->constraint = $constraint;
307 return $this;
308 }
309
310 /**
311 * Sets the statement of this query programmatically. If you use this, you will lose the abstraction from a concrete storage
312 * backend (database).
313 *
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
317 */
318 public function statement($statement, array $parameters = array()) {
319 $this->statement = $this->qomFactory->statement($statement, $parameters);
320 return $this;
321 }
322
323 /**
324 * Returns the statement of this query.
325 *
326 * @return Tx_Extbase_Persistence_QOM_Statement
327 */
328 public function getStatement() {
329 return $this->statement;
330 }
331
332 /**
333 * Gets the constraint for this query.
334 *
335 * @return Tx_Extbase_Persistence_QOM_Constraint the constraint, or null if none
336 * @author Karsten Dambekalns <karsten@typo3.org>
337 * @api
338 */
339 public function getConstraint() {
340 return $this->constraint;
341 }
342
343 /**
344 * Performs a logical conjunction of the given constraints.
345 *
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
350 */
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,
359 $constraint
360 );
361 }
362 } else {
363 throw new Tx_Extbase_Persistence_Exception_InvalidNumberOfConstraints('There must be at least two constraints. Got only ' . func_num_args() . '.', 1268056288);
364 }
365 return $resultingConstraint;
366 }
367
368 /**
369 * Performs a logical conjunction of the given constraints.
370 *
371 * @param array $constraints An array of constraints
372 * @return Tx_Extbase_Persistence_QOM_AndInterface
373 */
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,
384 $constraint
385 );
386 }
387 }
388 return $resultingConstraint;
389 }
390
391 /**
392 * Performs a logical disjunction of the two given constraints
393 *
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
398 */
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,
407 $constraint
408 );
409 }
410 } else {
411 throw new Tx_Extbase_Persistence_Exception_InvalidNumberOfConstraints('There must be at least two constraints. Got only ' . func_num_args() . '.', 1268056288);
412 }
413 return $resultingConstraint;
414 }
415
416 /**
417 * Performs a logical conjunction of the given constraints.
418 *
419 * @param array $constraints An array of constraints
420 * @return Tx_Extbase_Persistence_QOM_AndInterface
421 */
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,
432 $constraint
433 );
434 }
435 }
436 return $resultingConstraint;
437 }
438
439 /**
440 * Performs a logical negation of the given constraint
441 *
442 * @param object $constraint Constraint to negate
443 * @return Tx_Extbase_Persistence_QOM_NotInterface
444 * @api
445 */
446 public function logicalNot($constraint) {
447 return $this->qomFactory->not($constraint);
448 }
449
450 /**
451 * Matches against the (internal) uid.
452 *
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
456 */
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,
462 $operand
463 );
464 }
465
466 /**
467 * Returns an equals criterion used for matching objects against a query
468 *
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
473 * @api
474 */
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,
480 $operand
481 );
482 } else {
483 $comparison = $this->qomFactory->comparison(
484 $this->qomFactory->lowerCase(
485 $this->qomFactory->propertyValue($propertyName, $this->getSelectorName())
486 ),
487 Tx_Extbase_Persistence_QueryInterface::OPERATOR_EQUAL_TO,
488 strtolower($operand)
489 );
490 }
491
492 return $comparison;
493 }
494
495 /**
496 * Returns a like criterion used for matching objects against a query
497 *
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
501 * @api
502 */
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,
507 $operand
508 );
509 }
510
511 /**
512 * Returns a "contains" criterion used for matching objects against a query.
513 * It matches if the multivalued property contains the given operand.
514 *
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
518 * @api
519 */
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,
524 $operand
525 );
526 }
527
528 /**
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.
531 *
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
535 * @api
536 */
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);
540 }
541
542 return $this->qomFactory->comparison(
543 $this->qomFactory->propertyValue($propertyName, $this->getSelectorName()),
544 Tx_Extbase_Persistence_QueryInterface::OPERATOR_IN,
545 $operand
546 );
547 }
548
549 /**
550 * Returns a less than criterion used for matching objects against a query
551 *
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
555 * @api
556 */
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,
561 $operand
562 );
563 }
564
565 /**
566 * Returns a less or equal than criterion used for matching objects against a query
567 *
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
571 * @api
572 */
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,
577 $operand
578 );
579 }
580
581 /**
582 * Returns a greater than criterion used for matching objects against a query
583 *
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
587 * @api
588 */
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,
593 $operand
594 );
595 }
596
597 /**
598 * Returns a greater than or equal criterion used for matching objects against a query
599 *
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
603 * @api
604 */
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,
609 $operand
610 );
611 }
612
613 }
614 ?>