[TASK] Replace inject methods with @inject
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Persistence / Generic / Query.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Persistence\Generic;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2010-2013 Extbase Team (http://forge.typo3.org/projects/typo3v4-mvc)
8 * Extbase is a backport of TYPO3 Flow. All credits go to the TYPO3 Flow team.
9 * All rights reserved
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 * A copy is found in the textfile GPL.txt and important notices to the license
20 * from the author is found in LICENSE.txt distributed with these scripts.
21 *
22 *
23 * This script is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * This copyright notice MUST APPEAR in all copies of the script!
29 ***************************************************************/
30 /**
31 * The Query class used to run queries against the database
32 *
33 * @api
34 */
35 class Query implements \TYPO3\CMS\Extbase\Persistence\QueryInterface {
36
37 /**
38 * An inner join.
39 */
40 const JCR_JOIN_TYPE_INNER = '{http://www.jcp.org/jcr/1.0}joinTypeInner';
41
42 /**
43 * A left-outer join.
44 */
45 const JCR_JOIN_TYPE_LEFT_OUTER = '{http://www.jcp.org/jcr/1.0}joinTypeLeftOuter';
46
47 /**
48 * A right-outer join.
49 */
50 const JCR_JOIN_TYPE_RIGHT_OUTER = '{http://www.jcp.org/jcr/1.0}joinTypeRightOuter';
51
52 /**
53 * Charset of strings in QOM
54 */
55 const CHARSET = 'utf-8';
56
57 /**
58 * @var string
59 */
60 protected $type;
61
62 /**
63 * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
64 * @inject
65 */
66 protected $objectManager;
67
68 /**
69 * @var \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper
70 * @inject
71 */
72 protected $dataMapper;
73
74 /**
75 * @var \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface
76 * @inject
77 */
78 protected $persistenceManager;
79
80 /**
81 * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory
82 * @inject
83 */
84 protected $qomFactory;
85
86 /**
87 * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface
88 */
89 protected $source;
90
91 /**
92 * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface
93 */
94 protected $constraint;
95
96 /**
97 * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Statement
98 */
99 protected $statement;
100
101 /**
102 * @var int
103 */
104 protected $orderings = array();
105
106 /**
107 * @var int
108 */
109 protected $limit;
110
111 /**
112 * @var int
113 */
114 protected $offset;
115
116 /**
117 * The query settings.
118 *
119 * @var \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface
120 */
121 protected $querySettings;
122
123 /**
124 * Constructs a query object working on the given class name
125 *
126 * @param string $type
127 */
128 public function __construct($type) {
129 $this->type = $type;
130 }
131
132 /**
133 * Sets the Query Settings. These Query settings must match the settings expected by
134 * the specific Storage Backend.
135 *
136 * @param \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings The Query Settings
137 * @return void
138 * @api This method is not part of FLOW3 API
139 */
140 public function setQuerySettings(\TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings) {
141 $this->querySettings = $querySettings;
142 }
143
144 /**
145 * Returns the Query Settings.
146 *
147 * @throws Exception
148 * @return \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings The Query Settings
149 * @api This method is not part of FLOW3 API
150 */
151 public function getQuerySettings() {
152 if (!$this->querySettings instanceof \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface) {
153 throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception('Tried to get the query settings without seting them before.', 1248689115);
154 }
155 return $this->querySettings;
156 }
157
158 /**
159 * Returns the type this query cares for.
160 *
161 * @return string
162 * @api
163 */
164 public function getType() {
165 return $this->type;
166 }
167
168 /**
169 * Sets the source to fetch the result from
170 *
171 * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source
172 */
173 public function setSource(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source) {
174 $this->source = $source;
175 }
176
177 /**
178 * Returns the selectorn name or an empty string, if the source is not a selector
179 * TODO This has to be checked at another place
180 *
181 * @return string The selector name
182 */
183 protected function getSelectorName() {
184 if ($this->getSource() instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SelectorInterface) {
185 return $this->source->getSelectorName();
186 } else {
187 return '';
188 }
189 }
190
191 /**
192 * Gets the node-tuple source for this query.
193 *
194 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface the node-tuple source; non-null
195 */
196 public function getSource() {
197 if ($this->source === NULL) {
198 $this->source = $this->qomFactory->selector($this->getType(), $this->dataMapper->convertClassNameToTableName($this->getType()));
199 }
200 return $this->source;
201 }
202
203 /**
204 * Executes the query against the database and returns the result
205 *
206 * @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface|array The query result object or an array if $this->getQuerySettings()->getReturnRawQueryResult() is TRUE
207 * @api
208 */
209 public function execute() {
210 if ($this->getQuerySettings()->getReturnRawQueryResult() === TRUE) {
211 return $this->persistenceManager->getObjectDataByQuery($this);
212 } else {
213 return $this->objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\QueryResultInterface', $this);
214 }
215 }
216
217 /**
218 * Sets the property names to order the result by. Expected like this:
219 * array(
220 * 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
221 * 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
222 * )
223 * where 'foo' and 'bar' are property names.
224 *
225 * @param array $orderings The property names to order by
226 * @return \TYPO3\CMS\Extbase\Persistence\QueryInterface
227 * @api
228 */
229 public function setOrderings(array $orderings) {
230 $this->orderings = $orderings;
231 return $this;
232 }
233
234 /**
235 * Returns the property names to order the result by. Like this:
236 * array(
237 * 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
238 * 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
239 * )
240 *
241 * @return array
242 * @api
243 */
244 public function getOrderings() {
245 return $this->orderings;
246 }
247
248 /**
249 * Sets the maximum size of the result set to limit. Returns $this to allow
250 * for chaining (fluid interface)
251 *
252 * @param integer $limit
253 * @throws \InvalidArgumentException
254 * @return \TYPO3\CMS\Extbase\Persistence\QueryInterface
255 * @api
256 */
257 public function setLimit($limit) {
258 if (!is_int($limit) || $limit < 1) {
259 throw new \InvalidArgumentException('The limit must be an integer >= 1', 1245071870);
260 }
261 $this->limit = $limit;
262 return $this;
263 }
264
265 /**
266 * Resets a previously set maximum size of the result set. Returns $this to allow
267 * for chaining (fluid interface)
268 *
269 * @return \TYPO3\CMS\Extbase\Persistence\QueryInterface
270 * @api
271 */
272 public function unsetLimit() {
273 unset($this->limit);
274 return $this;
275 }
276
277 /**
278 * Returns the maximum size of the result set to limit.
279 *
280 * @return integer
281 * @api
282 */
283 public function getLimit() {
284 return $this->limit;
285 }
286
287 /**
288 * Sets the start offset of the result set to offset. Returns $this to
289 * allow for chaining (fluid interface)
290 *
291 * @param integer $offset
292 * @throws \InvalidArgumentException
293 * @return \TYPO3\CMS\Extbase\Persistence\QueryInterface
294 * @api
295 */
296 public function setOffset($offset) {
297 if (!is_int($offset) || $offset < 0) {
298 throw new \InvalidArgumentException('The offset must be a positive integer', 1245071872);
299 }
300 $this->offset = $offset;
301 return $this;
302 }
303
304 /**
305 * Returns the start offset of the result set.
306 *
307 * @return integer
308 * @api
309 */
310 public function getOffset() {
311 return $this->offset;
312 }
313
314 /**
315 * The constraint used to limit the result set. Returns $this to allow
316 * for chaining (fluid interface)
317 *
318 * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint
319 * @return \TYPO3\CMS\Extbase\Persistence\QueryInterface
320 * @api
321 */
322 public function matching($constraint) {
323 $this->constraint = $constraint;
324 return $this;
325 }
326
327 /**
328 * Sets the statement of this query programmatically. If you use this, you will lose the abstraction from a concrete storage
329 * backend (database).
330 *
331 * @param string $statement The statement
332 * @param array $parameters An array of parameters. These will be bound to placeholders '?' in the $statement.
333 * @return \TYPO3\CMS\Extbase\Persistence\QueryInterface
334 */
335 public function statement($statement, array $parameters = array()) {
336 $this->statement = $this->qomFactory->statement($statement, $parameters);
337 return $this;
338 }
339
340 /**
341 * Returns the statement of this query.
342 *
343 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Statement
344 */
345 public function getStatement() {
346 return $this->statement;
347 }
348
349 /**
350 * Gets the constraint for this query.
351 *
352 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Constraint the constraint, or null if none
353 * @api
354 */
355 public function getConstraint() {
356 return $this->constraint;
357 }
358
359 /**
360 * Performs a logical conjunction of the given constraints. The method takes one or more contraints and concatenates them with a boolean AND.
361 * It also scepts a single array of constraints to be concatenated.
362 *
363 * @param mixed $constraint1 The first of multiple constraints or an array of constraints.
364 * @throws Exception\InvalidNumberOfConstraintsException
365 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\AndInterface
366 * @api
367 */
368 public function logicalAnd($constraint1) {
369 if (is_array($constraint1)) {
370 $resultingConstraint = array_shift($constraint1);
371 $constraints = $constraint1;
372 } else {
373 $constraints = func_get_args();
374 $resultingConstraint = array_shift($constraints);
375 }
376 if ($resultingConstraint === NULL) {
377 throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\InvalidNumberOfConstraintsException('There must be at least one constraint or a non-empty array of constraints given.', 1268056288);
378 }
379 foreach ($constraints as $constraint) {
380 $resultingConstraint = $this->qomFactory->_and($resultingConstraint, $constraint);
381 }
382 return $resultingConstraint;
383 }
384
385 /**
386 * Performs a logical disjunction of the two given constraints
387 *
388 * @param mixed $constraint1 The first of multiple constraints or an array of constraints.
389 * @throws Exception\InvalidNumberOfConstraintsException
390 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\OrInterface
391 * @api
392 */
393 public function logicalOr($constraint1) {
394 if (is_array($constraint1)) {
395 $resultingConstraint = array_shift($constraint1);
396 $constraints = $constraint1;
397 } else {
398 $constraints = func_get_args();
399 $resultingConstraint = array_shift($constraints);
400 }
401 if ($resultingConstraint === NULL) {
402 throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\InvalidNumberOfConstraintsException('There must be at least one constraint or a non-empty array of constraints given.', 1268056288);
403 }
404 foreach ($constraints as $constraint) {
405 $resultingConstraint = $this->qomFactory->_or($resultingConstraint, $constraint);
406 }
407 return $resultingConstraint;
408 }
409
410 /**
411 * Performs a logical negation of the given constraint
412 *
413 * @param object $constraint Constraint to negate
414 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\NotInterface
415 * @api
416 */
417 public function logicalNot($constraint) {
418 return $this->qomFactory->not($constraint);
419 }
420
421 /**
422 * Returns an equals criterion used for matching objects against a query
423 *
424 * @param string $propertyName The name of the property to compare against
425 * @param mixed $operand The value to compare with
426 * @param boolean $caseSensitive Whether the equality test should be done case-sensitive
427 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
428 * @api
429 */
430 public function equals($propertyName, $operand, $caseSensitive = TRUE) {
431 if (is_object($operand) || $caseSensitive) {
432 $comparison = $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), \TYPO3\CMS\Extbase\Persistence\QueryInterface::OPERATOR_EQUAL_TO, $operand);
433 } else {
434 $comparison = $this->qomFactory->comparison($this->qomFactory->lowerCase($this->qomFactory->propertyValue($propertyName, $this->getSelectorName())), \TYPO3\CMS\Extbase\Persistence\QueryInterface::OPERATOR_EQUAL_TO, \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Charset\\CharsetConverter')->conv_case(\TYPO3\CMS\Extbase\Persistence\Generic\Query::CHARSET, $operand, 'toLower'));
435 }
436 return $comparison;
437 }
438
439 /**
440 * Returns a like criterion used for matching objects against a query
441 *
442 * @param string $propertyName The name of the property to compare against
443 * @param mixed $operand The value to compare with
444 * @param boolean $caseSensitive Whether the matching should be done case-sensitive
445 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
446 * @api
447 */
448 public function like($propertyName, $operand, $caseSensitive = TRUE) {
449 return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), \TYPO3\CMS\Extbase\Persistence\QueryInterface::OPERATOR_LIKE, $operand);
450 }
451
452 /**
453 * Returns a "contains" criterion used for matching objects against a query.
454 * It matches if the multivalued property contains the given operand.
455 *
456 * @param string $propertyName The name of the (multivalued) property to compare against
457 * @param mixed $operand The value to compare with
458 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
459 * @api
460 */
461 public function contains($propertyName, $operand) {
462 return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), \TYPO3\CMS\Extbase\Persistence\QueryInterface::OPERATOR_CONTAINS, $operand);
463 }
464
465 /**
466 * Returns an "in" criterion used for matching objects against a query. It
467 * matches if the property's value is contained in the multivalued operand.
468 *
469 * @param string $propertyName The name of the property to compare against
470 * @param mixed $operand The value to compare with, multivalued
471 * @throws Exception\UnexpectedTypeException
472 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
473 * @api
474 */
475 public function in($propertyName, $operand) {
476 if (!is_array($operand) && !$operand instanceof \ArrayAccess && !$operand instanceof \Traversable) {
477 throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException('The "in" operator must be given a mutlivalued operand (array, ArrayAccess, Traversable).', 1264678095);
478 }
479 return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), \TYPO3\CMS\Extbase\Persistence\QueryInterface::OPERATOR_IN, $operand);
480 }
481
482 /**
483 * Returns a less than criterion used for matching objects against a query
484 *
485 * @param string $propertyName The name of the property to compare against
486 * @param mixed $operand The value to compare with
487 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
488 * @api
489 */
490 public function lessThan($propertyName, $operand) {
491 return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), \TYPO3\CMS\Extbase\Persistence\QueryInterface::OPERATOR_LESS_THAN, $operand);
492 }
493
494 /**
495 * Returns a less or equal than criterion used for matching objects against a query
496 *
497 * @param string $propertyName The name of the property to compare against
498 * @param mixed $operand The value to compare with
499 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
500 * @api
501 */
502 public function lessThanOrEqual($propertyName, $operand) {
503 return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), \TYPO3\CMS\Extbase\Persistence\QueryInterface::OPERATOR_LESS_THAN_OR_EQUAL_TO, $operand);
504 }
505
506 /**
507 * Returns a greater than criterion used for matching objects against a query
508 *
509 * @param string $propertyName The name of the property to compare against
510 * @param mixed $operand The value to compare with
511 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
512 * @api
513 */
514 public function greaterThan($propertyName, $operand) {
515 return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), \TYPO3\CMS\Extbase\Persistence\QueryInterface::OPERATOR_GREATER_THAN, $operand);
516 }
517
518 /**
519 * Returns a greater than or equal criterion used for matching objects against a query
520 *
521 * @param string $propertyName The name of the property to compare against
522 * @param mixed $operand The value to compare with
523 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
524 * @api
525 */
526 public function greaterThanOrEqual($propertyName, $operand) {
527 return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), \TYPO3\CMS\Extbase\Persistence\QueryInterface::OPERATOR_GREATER_THAN_OR_EQUAL_TO, $operand);
528 }
529
530 /**
531 * @return void
532 */
533 public function __wakeup() {
534 $this->objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
535 $this->persistenceManager = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\PersistenceManagerInterface');
536 $this->dataMapper = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Mapper\\DataMapper');
537 $this->qomFactory = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Qom\\QueryObjectModelFactory');
538 }
539
540 /**
541 * @return array
542 */
543 public function __sleep() {
544 return array('type', 'source', 'constraint', 'statement', 'orderings', 'limit', 'offset', 'querySettings');
545 }
546
547 /**
548 * Returns the query result count.
549 *
550 * @return integer The query result count
551 * @api
552 */
553 public function count() {
554 return $this->execute()->count();
555 }
556
557 /**
558 * Returns an "isEmpty" criterion used for matching objects against a query.
559 * It matches if the multivalued property contains no values or is NULL.
560 *
561 * @param string $propertyName The name of the multivalued property to compare against
562 * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\NotImplementedException
563 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException if used on a single-valued property
564 * @api
565 */
566 public function isEmpty($propertyName) {
567 throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\NotImplementedException(__METHOD__);
568 }
569 }
570
571 ?>