Extbase:
[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: Query.php 658 2009-05-16 13:54:16Z jocrau $
34 * @scope prototype
35 */
36 class Tx_Extbase_Persistence_Query implements Tx_Extbase_Persistence_QueryInterface {
37 // SK: Is "limit" and "order" and "offset" evaluated?
38 /**
39 * @var string
40 */
41 protected $className;
42
43 /**
44 * @var Tx_Extbase_Persistence_DataMapper
45 */
46 protected $dataMapper;
47
48 /**
49 * @var Tx_Extbase_Persistence_QOM_QueryObjectModelFactoryInterface
50 */
51 protected $QOMFactory;
52
53 /**
54 * @var Tx_Extbase_Persistence_ValueFactoryInterface
55 */
56 protected $valueFactory;
57
58 /**
59 * @var Tx_Extbase_Persistence_ManagerInterface
60 */
61 protected $persistenceManager;
62
63 /**
64 * @var Tx_Extbase_Persistence_QOM_SourceInterface
65 */
66 protected $source;
67
68 /**
69 * @var Tx_Extbase_Persistence_QOM_ConstraintInterface
70 */
71 protected $constraint;
72
73 /**
74 * An array of named variables and their values from the operators
75 * @var array
76 */
77 protected $operands = array();
78
79 /**
80 * @var int
81 */
82 protected $orderings = array();
83
84 /**
85 * @var int
86 */
87 protected $columns = array();
88
89 /**
90 * @var int
91 */
92 protected $limit;
93
94 /**
95 * @var int
96 */
97 protected $offset;
98
99 /**
100 * Constructs a query object working on the given class name
101 *
102 * @param string $className
103 */
104 public function __construct($className) {
105 $this->className = $className;
106 }
107
108 /**
109 * Injects the persistence manager, used to fetch the CR session
110 *
111 * @param Tx_Extbase_Persistence_ManagerInterface $persistenceManager
112 * @return void
113 */
114 public function injectPersistenceManager(Tx_Extbase_Persistence_ManagerInterface $persistenceManager) {
115 $this->persistenceManager = $persistenceManager;
116 $this->QOMFactory = $this->persistenceManager->getBackend()->getQOMFactory();
117 $this->valueFactory = $this->persistenceManager->getBackend()->getValueFactory();
118 }
119
120 /**
121 * Injects the DataMapper to map nodes to objects
122 *
123 * @param Tx_Extbase_Persistence_Mapper_DataMapper $dataMapper
124 * @return void
125 */
126 public function injectDataMapper(Tx_Extbase_Persistence_Mapper_DataMapper $dataMapper) {
127 $this->dataMapper = $dataMapper;
128 }
129
130 /**
131 * Returns the class name the query handles
132 *
133 * @return string The class name
134 */
135 public function getClassName() {
136 $this->className;
137 }
138
139 /**
140 * Sets the source to fetch the result from
141 *
142 * @param Tx_Extbase_Persistence_QOM_SourceInterface $source
143 */
144 public function setSource(Tx_Extbase_Persistence_QOM_SourceInterface $source) {
145 $this->source = $source;
146 }
147
148 /**
149 * Returns the source to fetch the result from. If the source is not set, it will be generated from the given class name
150 *
151 * @return Tx_Extbase_Persistence_QOM_SourceInterface The source
152 */
153 protected function getSource() {
154 if ($this->source === NULL) {
155 $this->source = $this->QOMFactory->selector($this->dataMapper->convertClassNameToSelectorName($this->className));
156 }
157 return $this->source;
158 }
159
160 /**
161 * Executes the query against the database and returns the result
162 *
163 * @return Tx_Extbase_Persistence_QueryResultInterface The query result
164 */
165 public function execute() {
166 $query = $this->QOMFactory->createQuery(
167 $this->getSource(),
168 $this->constraint,
169 $this->orderings,
170 $this->columns // TODO implement selection of columns
171 );
172 foreach ($this->operands as $name => $value) {
173 $query->bindValue($name, $this->valueFactory->createValue($value));
174 }
175 $result = $query->execute();
176
177 return $this->dataMapper->map($this->className, $result->getRows());
178 }
179
180 /**
181 * Sets the property names to order the result by. Expected like this:
182 * array(
183 * 'foo' => Tx_Extbase_Persistence_QueryInterface::ORDER_ASCENDING,
184 * 'bar' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING
185 * )
186 *
187 * @param array $orderings The property names to order by
188 * @return Tx_Extbase_Persistence_QueryInterface
189 */
190 public function setOrderings(array $orderings) {
191 $this->orderings = $orderings;
192 }
193
194 /**
195 * Sets the maximum size of the result set to limit. Returns $this to allow
196 * for chaining (fluid interface)
197 *
198 * @param integer $limit
199 * @return Tx_Extbase_Persistence_QueryInterface
200 */
201 public function setLimit($limit) {
202 if (!is_int($limit) || $limit < 1) throw new InvalidArgumentException('The limit must be an integer >= 1', 1245071870);
203 $this->limit = $limit;
204 return $this;
205 }
206
207 /**
208 * Sets the start offset of the result set to offset. Returns $this to
209 * allow for chaining (fluid interface)
210 *
211 * @param integer $offset
212 * @return Tx_Extbase_Persistence_QueryInterface
213 */
214 public function setOffset($offset) {
215 if (!is_int($offset) || $offset < 0) throw new InvalidArgumentException('The limit must be a positive integer', 1245071872);
216 $this->offset = $offset;
217 }
218
219 /**
220 * The constraint used to limit the result set. Returns $this to allow
221 * for chaining (fluid interface)
222 *
223 * @param Tx_Extbase_Persistence_QOM_ConstraintInterface $constraint
224 * @return Tx_Extbase_Persistence_QueryInterface
225 */
226 public function matching($constraint) {
227 $this->constraint = $constraint;
228 return $this;
229 }
230
231 /**
232 * Performs a logical conjunction of the two given constraints.
233 *
234 * @param object $constraint1 First constraint
235 * @param object $constraint2 Second constraint
236 * @return Tx_Extbase_Persistence_QOM_AndInterface
237 */
238 public function logicalAnd($constraint1, $constraint2) {
239 return $this->QOMFactory->_and(
240 $constraint1,
241 $constraint2
242 );
243 }
244
245 /**
246 * Performs a logical disjunction of the two given constraints
247 *
248 * @param object $constraint1 First constraint
249 * @param object $constraint2 Second constraint
250 * @return Tx_Extbase_Persistence_QOM_OrInterface
251 */
252 public function logicalOr($constraint1, $constraint2) {
253 return $this->QOMFactory->_or(
254 $constraint1,
255 $constraint2
256 );
257 }
258
259 /**
260 * Performs a logical negation of the given constraint
261 *
262 * @param object $constraint Constraint to negate
263 * @return Tx_Extbase_Persistence_QOM_NotInterface
264 */
265 public function logicalNot($constraint) {
266 return $this->QOMFactory->not($constraint);
267 }
268
269 /**
270 * Matches against the (internal) uid.
271 *
272 * @param int $uid The uid to match against
273 * @return Tx_Extbase_Persistence_QOM_ComparisonInterface
274 */
275 public function withUid($uid) {
276 $sourceSelectorName = $this->getSource()->getSelectorName();
277 $this->operands['uid'] = $uid;
278 return $this->QOMFactory->comparison(
279 $this->QOMFactory->propertyValue('uid', $sourceSelectorName),
280 Tx_Extbase_Persistence_QOM_QueryObjectModelConstantsInterface::JCR_OPERATOR_EQUAL_TO,
281 $this->QOMFactory->bindVariable('uid')
282 );
283 }
284
285 /**
286 * Returns an equals criterion used for matching objects against a query
287 *
288 * @param string $propertyName The name of the property to compare against
289 * @param mixed $operand The value to compare with
290 * @param boolean $caseSensitive Whether the equality test should be done case-sensitive
291 * @return Tx_Extbase_Persistence_QOM_ComparisonInterface
292 */
293 public function equals($propertyName, $operand, $caseSensitive = TRUE) {
294 $source = $this->getSource();
295 if ($source instanceof Tx_Extbase_Persistence_QOM_SelectorInterface) {
296 $sourceSelectorName = $this->getSource()->getSelectorName();
297 }
298 // TODO $sourceSelectorName might not be initialized
299
300 if (is_object($operand) && !($operand instanceof DateTime)) {
301 $operand = $this->persistenceManager->getBackend()->getUidByObject($operand);
302 $left = $this->getSource();
303 $columnMap = $this->dataMapper->getDataMap($this->className)->getColumnMap($propertyName);
304 $childSelectorName = $columnMap->getChildTableName();
305 $right = $this->QOMFactory->selector($childSelectorName);
306 $joinCondition = $this->QOMFactory->childNodeJoinCondition($childSelectorName, $parentSelectorName);
307
308 $this->source = $this->QOMFactory->join(
309 $left,
310 $right,
311 Tx_Extbase_Persistence_QOM_QueryObjectModelConstantsInterface::JCR_JOIN_TYPE_INNER,
312 $joinCondition
313 );
314
315 $comparison = $this->QOMFactory->comparison(
316 $this->QOMFactory->propertyValue($propertyName, $sourceSelectorName),
317 Tx_Extbase_Persistence_QOM_QueryObjectModelConstantsInterface::JCR_OPERATOR_EQUAL_TO,
318 $this->QOMFactory->bindVariable($propertyName)
319 );
320
321 $this->operands[$propertyName] = $operand;
322 } else {
323 if ($caseSensitive) {
324 $comparison = $this->QOMFactory->comparison(
325 $this->QOMFactory->propertyValue($propertyName, $sourceSelectorName),
326 Tx_Extbase_Persistence_QOM_QueryObjectModelConstantsInterface::JCR_OPERATOR_EQUAL_TO,
327 $this->QOMFactory->bindVariable($propertyName)
328 );
329 } else {
330 $comparison = $this->QOMFactory->comparison(
331 $this->QOMFactory->lowerCase(
332 $this->QOMFactory->propertyValue($propertyName, $sourceSelectorName)
333 ),
334 Tx_Extbase_Persistence_QOM_QueryObjectModelConstantsInterface::JCR_OPERATOR_EQUAL_TO,
335 $this->QOMFactory->bindVariable($propertyName)
336 );
337 }
338
339 if ($caseSensitive) {
340 $this->operands[$propertyName] = $operand;
341 } else {
342 $this->operands[$propertyName] = strtolower($operand);
343 }
344 }
345
346 return $comparison;
347 }
348
349 /**
350 * Returns a like criterion used for matching objects against a query
351 *
352 * @param string $propertyName The name of the property to compare against
353 * @param mixed $operand The value to compare with
354 * @return Tx_Extbase_Persistence_QOM_ComparisonInterface
355 */
356 public function like($propertyName, $operand) {
357 $this->operands[$propertyName] = $operand;
358 return $this->QOMFactory->comparison(
359 $this->QOMFactory->propertyValue($propertyName, $this->getSource()),
360 Tx_Extbase_Persistence_QOM_QueryObjectModelConstantsInterface::JCR_OPERATOR_LIKE,
361 $this->QOMFactory->bindVariable($propertyName)
362 );
363 }
364
365 /**
366 * Returns a less than criterion used for matching objects against a query
367 *
368 * @param string $propertyName The name of the property to compare against
369 * @param mixed $operand The value to compare with
370 * @return Tx_Extbase_Persistence_QOM_ComparisonInterface
371 */
372 public function lessThan($propertyName, $operand) {
373 $sourceSelectorName = $this->getSource()->getSelectorName();
374 $this->operands[$propertyName] = $operand;
375 return $this->QOMFactory->comparison(
376 $this->QOMFactory->propertyValue($propertyName, $sourceSelectorName),
377 Tx_Extbase_Persistence_QOM_QueryObjectModelConstantsInterface::JCR_OPERATOR_LESS_THAN,
378 $this->QOMFactory->bindVariable($propertyName)
379 );
380 }
381
382 /**
383 * Returns a less or equal than criterion used for matching objects against a query
384 *
385 * @param string $propertyName The name of the property to compare against
386 * @param mixed $operand The value to compare with
387 * @return Tx_Extbase_Persistence_QOM_ComparisonInterface
388 */
389 public function lessThanOrEqual($propertyName, $operand) {
390 $sourceSelectorName = $this->getSource()->getSelectorName();
391 $this->operands[$propertyName] = $operand;
392 return $this->QOMFactory->comparison(
393 $this->QOMFactory->propertyValue($propertyName, $sourceSelectorName),
394 Tx_Extbase_Persistence_QOM_QueryObjectModelConstantsInterface::JCR_OPERATOR_LESS_THAN_OR_EQUAL_TO,
395 $this->QOMFactory->bindVariable($propertyName)
396 );
397 }
398
399 /**
400 * Returns a greater than criterion used for matching objects against a query
401 *
402 * @param string $propertyName The name of the property to compare against
403 * @param mixed $operand The value to compare with
404 * @return Tx_Extbase_Persistence_QOM_ComparisonInterface
405 */
406 public function greaterThan($propertyName, $operand) {
407 $sourceSelectorName = $this->getSource()->getSelectorName();
408 $this->operands[$propertyName] = $operand;
409 return $this->QOMFactory->comparison(
410 $this->QOMFactory->propertyValue($propertyName, $sourceSelectorName),
411 Tx_Extbase_Persistence_QOM_QueryObjectModelConstantsInterface::JCR_OPERATOR_GREATER_THAN,
412 $this->QOMFactory->bindVariable($propertyName)
413 );
414 }
415
416 /**
417 * Returns a greater than or equal criterion used for matching objects against a query
418 *
419 * @param string $propertyName The name of the property to compare against
420 * @param mixed $operand The value to compare with
421 * @return Tx_Extbase_Persistence_QOM_ComparisonInterface
422 */
423 public function greaterThanOrEqual($propertyName, $operand) {
424 $sourceSelectorName = $this->getSource()->getSelectorName();
425 $this->operands[$propertyName] = $operand;
426 return $this->QOMFactory->comparison(
427 $this->QOMFactory->propertyValue($propertyName, $sourceSelectorName),
428 Tx_Extbase_Persistence_QOM_QueryObjectModelConstantsInterface::JCR_OPERATOR_GREATER_THAN_OR_EQUAL_TO,
429 $this->QOMFactory->bindVariable($propertyName)
430 );
431 }
432
433 }
434 ?>