edb144c887b4b60ff96321aae02c29129df54a11
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Persistence / Repository.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 base repository - will usually be extended by a more concrete repository.
30 *
31 * @package Extbase
32 * @subpackage Persistence
33 * @version $ID:$
34 * @api
35 */
36 class Tx_Extbase_Persistence_Repository implements Tx_Extbase_Persistence_RepositoryInterface, t3lib_Singleton {
37
38 /**
39 * @var Tx_Extbase_Persistence_IdentityMap
40 **/
41 protected $identityMap;
42
43 /**
44 * Objects of this repository
45 *
46 * @var Tx_Extbase_Persistence_ObjectStorage
47 */
48 protected $addedObjects;
49
50 /**
51 * Objects removed but not found in $this->addedObjects at removal time
52 *
53 * @var Tx_Extbase_Persistence_ObjectStorage
54 */
55 protected $removedObjects;
56
57 /**
58 * @var Tx_Extbase_Persistence_QueryFactoryInterface
59 */
60 protected $queryFactory;
61
62 /**
63 * @var Tx_Extbase_Persistence_ManagerInterface
64 */
65 protected $persistenceManager;
66
67 /**
68 * @var Tx_Extbase_Object_ObjectManagerInterface
69 */
70 protected $objectManager;
71
72 /**
73 * @var string
74 */
75 protected $objectType;
76
77 /**
78 * @var array
79 */
80 protected $defaultOrderings = array();
81
82 /**
83 * @var Tx_Extbase_Persistence_QuerySettingsInterface
84 */
85 protected $defaultQuerySettings = NULL;
86
87 /**
88 * Constructs a new Repository
89 *
90 * @param Tx_Extbase_Object_ObjectManagerInterface $objectManager
91 */
92 public function __construct(Tx_Extbase_Object_ObjectManagerInterface $objectManager = NULL) {
93 $this->addedObjects = new Tx_Extbase_Persistence_ObjectStorage();
94 $this->removedObjects = new Tx_Extbase_Persistence_ObjectStorage();
95 $this->objectType = str_replace(array('_Repository_', 'Repository'), array('_Model_', ''), $this->getRepositoryClassName());
96
97 if ($objectManager === NULL) {
98 // Legacy creation, in case the object manager is NOT injected
99 // If ObjectManager IS there, then all properties are automatically injected
100 $this->objectManager = t3lib_div::makeInstance('Tx_Extbase_Object_ObjectManager');
101 $this->injectIdentityMap($this->objectManager->get('Tx_Extbase_Persistence_IdentityMap'));
102 $this->injectQueryFactory($this->objectManager->get('Tx_Extbase_Persistence_QueryFactory'));
103 $this->injectPersistenceManager($this->objectManager->get('Tx_Extbase_Persistence_Manager'));
104 } else {
105 $this->objectManager = $objectManager;
106 }
107 $this->initializeObject();
108 }
109
110 /**
111 * Life cycle method. You can override this in your own repository
112 *
113 * @return void
114 */
115 public function initializeObject() {
116 }
117
118 /**
119 * @param Tx_Extbase_Persistence_IdentityMap $identityMap
120 * @return void
121 */
122 public function injectIdentityMap(Tx_Extbase_Persistence_IdentityMap $identityMap) {
123 $this->identityMap = $identityMap;
124 }
125
126 /**
127 * @param Tx_Extbase_Persistence_QueryFactory $queryFactory
128 * @return void
129 */
130 public function injectQueryFactory(Tx_Extbase_Persistence_QueryFactory $queryFactory) {
131 $this->queryFactory = $queryFactory;
132 }
133
134 /**
135 * @param Tx_Extbase_Persistence_Manager $persistenceManager
136 * @return void
137 */
138 public function injectPersistenceManager(Tx_Extbase_Persistence_Manager $persistenceManager) {
139 $this->persistenceManager = $persistenceManager;
140 $this->persistenceManager->registerRepositoryClassName($this->getRepositoryClassName());
141 }
142
143 /**
144 * Adds an object to this repository
145 *
146 * @param object $object The object to add
147 * @return void
148 * @api
149 */
150 public function add($object) {
151 if (!($object instanceof $this->objectType)) {
152 throw new Tx_Extbase_Persistence_Exception_IllegalObjectType('The object given to add() was not of the type (' . $this->objectType . ') this repository manages.', 1248363335);
153 }
154
155 $this->addedObjects->attach($object);
156 $this->removedObjects->detach($object);
157 }
158
159 /**
160 * Removes an object from this repository.
161 *
162 * @param object $object The object to remove
163 * @return void
164 * @api
165 */
166 public function remove($object) {
167 if (!($object instanceof $this->objectType)) {
168 throw new Tx_Extbase_Persistence_Exception_IllegalObjectType('The object given to remove() was not of the type (' . $this->objectType . ') this repository manages.', 1248363335);
169 }
170
171 if ($this->addedObjects->contains($object)) {
172 $this->addedObjects->detach($object);
173 } else {
174 $this->removedObjects->attach($object);
175 }
176 }
177
178 /**
179 * Replaces an object by another.
180 *
181 * @param object $existingObject The existing object
182 * @param object $newObject The new object
183 * @return void
184 * @api
185 */
186 public function replace($existingObject, $newObject) {
187 if (!($existingObject instanceof $this->objectType)) {
188 throw new Tx_Extbase_Persistence_Exception_IllegalObjectType('The existing object given to replace was not of the type (' . $this->objectType . ') this repository manages.', 1248363434);
189 }
190 if (!($newObject instanceof $this->objectType)) {
191 throw new Tx_Extbase_Persistence_Exception_IllegalObjectType('The new object given to replace was not of the type (' . $this->objectType . ') this repository manages.', 1248363439);
192 }
193
194 $backend = $this->persistenceManager->getBackend();
195 $session = $this->persistenceManager->getSession();
196 $uuid = $backend->getIdentifierByObject($existingObject);
197 if ($uuid !== NULL) {
198 $backend->replaceObject($existingObject, $newObject);
199 $session->unregisterReconstitutedObject($existingObject);
200 $session->registerReconstitutedObject($newObject);
201
202 if ($this->removedObjects->contains($existingObject)) {
203 $this->removedObjects->detach($existingObject);
204 $this->removedObjects->attach($newObject);
205 }
206 } elseif ($this->addedObjects->contains($existingObject)) {
207 $this->addedObjects->detach($existingObject);
208 $this->addedObjects->attach($newObject);
209 } else {
210 throw new Tx_Extbase_Persistence_Exception_UnknownObject('The "existing object" is unknown to the persistence backend.', 1238068475);
211 }
212
213 }
214
215 /**
216 * Replaces an existing object with the same identifier by the given object
217 *
218 * @param object $modifiedObject The modified object
219 * @api
220 */
221 public function update($modifiedObject) {
222 if (!($modifiedObject instanceof $this->objectType)) {
223 throw new Tx_Extbase_Persistence_Exception_IllegalObjectType('The modified object given to update() was not of the type (' . $this->objectType . ') this repository manages.', 1249479625);
224 }
225
226 $uid = $modifiedObject->getUid();
227 if ($uid !== NULL) {
228 $existingObject = $this->findByUid($uid);
229 $this->replace($existingObject, $modifiedObject);
230 } else {
231 throw new Tx_Extbase_Persistence_Exception_UnknownObject('The "modified object" is does not have an existing counterpart in this repository.', 1249479819);
232 }
233 }
234
235 /**
236 * Returns all addedObjects that have been added to this repository with add().
237 *
238 * This is a service method for the persistence manager to get all addedObjects
239 * added to the repository. Those are only objects *added*, not objects
240 * fetched from the underlying storage.
241 *
242 * @return Tx_Extbase_Persistence_ObjectStorage the objects
243 */
244 public function getAddedObjects() {
245 return $this->addedObjects;
246 }
247
248 /**
249 * Returns an Tx_Extbase_Persistence_ObjectStorage with objects remove()d from the repository
250 * that had been persisted to the storage layer before.
251 *
252 * @return Tx_Extbase_Persistence_ObjectStorage the objects
253 */
254 public function getRemovedObjects() {
255 return $this->removedObjects;
256 }
257
258 /**
259 * Returns all objects of this repository
260 *
261 * @return array An array of objects, empty if no objects found
262 * @api
263 */
264 public function findAll() {
265 $result = $this->createQuery()->execute();
266 return $result;
267 }
268
269 /**
270 * Returns the total number objects of this repository.
271 *
272 * @return integer The object count
273 * @api
274 */
275 public function countAll() {
276 return $this->createQuery()->execute()->count();
277 }
278
279 /**
280 * Removes all objects of this repository as if remove() was called for
281 * all of them.
282 *
283 * @return void
284 * @api
285 */
286 public function removeAll() {
287 $this->addedObjects = new Tx_Extbase_Persistence_ObjectStorage();
288 foreach ($this->findAll() as $object) {
289 $this->remove($object);
290 }
291 }
292
293 /**
294 * Finds an object matching the given identifier.
295 *
296 * @param int $uid The identifier of the object to find
297 * @return object The matching object if found, otherwise NULL
298 * @api
299 */
300 public function findByUid($uid) {
301 if ($this->identityMap->hasIdentifier($uid, $this->objectType)) {
302 $object = $this->identityMap->getObjectByIdentifier($uid, $this->objectType);
303 } else {
304 $query = $this->createQuery();
305 $query->getQuerySettings()->setRespectSysLanguage(FALSE);
306 $query->getQuerySettings()->setRespectStoragePage(FALSE);
307 $object = $query->matching($query->equals('uid', $uid))
308 ->execute()
309 ->getFirst();
310 if ($object !== NULL) {
311 $this->identityMap->registerObject($object, $uid);
312 }
313 }
314 return $object;
315 }
316
317 /**
318 * Sets the property names to order the result by per default.
319 * Expected like this:
320 * array(
321 * 'foo' => Tx_Extbase_Persistence_QueryInterface::ORDER_ASCENDING,
322 * 'bar' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING
323 * )
324 *
325 * @param array $defaultOrderings The property names to order by
326 * @return void
327 * @api
328 */
329 public function setDefaultOrderings(array $defaultOrderings) {
330 $this->defaultOrderings = $defaultOrderings;
331 }
332
333 /**
334 * Sets the default query settings to be used in this repository
335 *
336 * @param Tx_Extbase_Persistence_QuerySettingsInterface $defaultQuerySettings The query settings to be used by default
337 * @return void
338 * @api
339 */
340 public function setDefaultQuerySettings(Tx_Extbase_Persistence_QuerySettingsInterface $defaultQuerySettings) {
341 $this->defaultQuerySettings = $defaultQuerySettings;
342 }
343
344 /**
345 * Returns a query for objects of this repository
346 *
347 * @return Tx_Extbase_Persistence_QueryInterface
348 * @api
349 */
350 public function createQuery() {
351 $query = $this->queryFactory->create($this->objectType);
352 if ($this->defaultOrderings !== array()) {
353 $query->setOrderings($this->defaultOrderings);
354 }
355 if ($this->defaultQuerySettings !== NULL) {
356 $query->setQuerySettings($this->defaultQuerySettings);
357 }
358 return $query;
359 }
360
361 /**
362 * Dispatches magic methods (findBy[Property]())
363 *
364 * @param string $methodName The name of the magic method
365 * @param string $arguments The arguments of the magic method
366 * @throws Tx_Extbase_Persistence_Exception_UnsupportedMethod
367 * @return void
368 * @api
369 */
370 public function __call($methodName, $arguments) {
371 if (substr($methodName, 0, 6) === 'findBy' && strlen($methodName) > 7) {
372 $propertyName = strtolower(substr(substr($methodName, 6), 0, 1) ) . substr(substr($methodName, 6), 1);
373 $query = $this->createQuery();
374 $result = $query->matching($query->equals($propertyName, $arguments[0]))
375 ->execute();
376 return $result;
377 } elseif (substr($methodName, 0, 9) === 'findOneBy' && strlen($methodName) > 10) {
378 $propertyName = strtolower(substr(substr($methodName, 9), 0, 1) ) . substr(substr($methodName, 9), 1);
379 $query = $this->createQuery();
380 $object = $query->matching($query->equals($propertyName, $arguments[0]))
381 ->setLimit(1)
382 ->execute()
383 ->getFirst();
384 return $object;
385 } elseif (substr($methodName, 0, 7) === 'countBy' && strlen($methodName) > 8) {
386 $propertyName = strtolower(substr(substr($methodName, 7), 0, 1) ) . substr(substr($methodName, 7), 1);
387 $query = $this->createQuery();
388 $result = $query->matching($query->equals($propertyName, $arguments[0]))
389 ->execute()
390 ->count();
391 return $result;
392 }
393 throw new Tx_Extbase_Persistence_Exception_UnsupportedMethod('The method "' . $methodName . '" is not supported by the repository.', 1233180480);
394 }
395
396 /**
397 * Returns the class name of this class.
398 *
399 * @return string Class name of the repository.
400 */
401 protected function getRepositoryClassName() {
402 return get_class($this);
403 }
404
405 }
406 ?>