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