f942e31d7b1571cf9a095ed693c0de88ae86dcb5
[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 }
108
109 /**
110 * @param Tx_Extbase_Persistence_IdentityMap $identityMap
111 * @return void
112 */
113 public function injectIdentityMap(Tx_Extbase_Persistence_IdentityMap $identityMap) {
114 $this->identityMap = $identityMap;
115 }
116
117 /**
118 * @param Tx_Extbase_Persistence_QueryFactory $queryFactory
119 * @return void
120 */
121 public function injectQueryFactory(Tx_Extbase_Persistence_QueryFactory $queryFactory) {
122 $this->queryFactory = $queryFactory;
123 }
124
125 /**
126 * @param Tx_Extbase_Persistence_Manager $persistenceManager
127 * @return void
128 */
129 public function injectPersistenceManager(Tx_Extbase_Persistence_Manager $persistenceManager) {
130 $this->persistenceManager = $persistenceManager;
131 $this->persistenceManager->registerRepositoryClassName($this->getRepositoryClassName());
132 }
133
134 /**
135 * Adds an object to this repository
136 *
137 * @param object $object The object to add
138 * @return void
139 * @api
140 */
141 public function add($object) {
142 if (!($object instanceof $this->objectType)) {
143 throw new Tx_Extbase_Persistence_Exception_IllegalObjectType('The object given to add() was not of the type (' . $this->objectType . ') this repository manages.', 1248363335);
144 }
145
146 $this->addedObjects->attach($object);
147 $this->removedObjects->detach($object);
148 }
149
150 /**
151 * Removes an object from this repository.
152 *
153 * @param object $object The object to remove
154 * @return void
155 * @api
156 */
157 public function remove($object) {
158 if (!($object instanceof $this->objectType)) {
159 throw new Tx_Extbase_Persistence_Exception_IllegalObjectType('The object given to remove() was not of the type (' . $this->objectType . ') this repository manages.', 1248363335);
160 }
161
162 if ($this->addedObjects->contains($object)) {
163 $this->addedObjects->detach($object);
164 } else {
165 $this->removedObjects->attach($object);
166 }
167 }
168
169 /**
170 * Replaces an object by another.
171 *
172 * @param object $existingObject The existing object
173 * @param object $newObject The new object
174 * @return void
175 * @api
176 */
177 public function replace($existingObject, $newObject) {
178 if (!($existingObject instanceof $this->objectType)) {
179 throw new Tx_Extbase_Persistence_Exception_IllegalObjectType('The existing object given to replace was not of the type (' . $this->objectType . ') this repository manages.', 1248363434);
180 }
181 if (!($newObject instanceof $this->objectType)) {
182 throw new Tx_Extbase_Persistence_Exception_IllegalObjectType('The new object given to replace was not of the type (' . $this->objectType . ') this repository manages.', 1248363439);
183 }
184
185 $backend = $this->persistenceManager->getBackend();
186 $session = $this->persistenceManager->getSession();
187 $uuid = $backend->getIdentifierByObject($existingObject);
188 if ($uuid !== NULL) {
189 $backend->replaceObject($existingObject, $newObject);
190 $session->unregisterReconstitutedObject($existingObject);
191 $session->registerReconstitutedObject($newObject);
192
193 if ($this->removedObjects->contains($existingObject)) {
194 $this->removedObjects->detach($existingObject);
195 $this->removedObjects->attach($newObject);
196 }
197 } elseif ($this->addedObjects->contains($existingObject)) {
198 $this->addedObjects->detach($existingObject);
199 $this->addedObjects->attach($newObject);
200 } else {
201 throw new Tx_Extbase_Persistence_Exception_UnknownObject('The "existing object" is unknown to the persistence backend.', 1238068475);
202 }
203
204 }
205
206 /**
207 * Replaces an existing object with the same identifier by the given object
208 *
209 * @param object $modifiedObject The modified object
210 * @api
211 */
212 public function update($modifiedObject) {
213 if (!($modifiedObject instanceof $this->objectType)) {
214 throw new Tx_Extbase_Persistence_Exception_IllegalObjectType('The modified object given to update() was not of the type (' . $this->objectType . ') this repository manages.', 1249479625);
215 }
216
217 $uid = $modifiedObject->getUid();
218 if ($uid !== NULL) {
219 $existingObject = $this->findByUid($uid);
220 $this->replace($existingObject, $modifiedObject);
221 } else {
222 throw new Tx_Extbase_Persistence_Exception_UnknownObject('The "modified object" is does not have an existing counterpart in this repository.', 1249479819);
223 }
224 }
225
226 /**
227 * Returns all addedObjects that have been added to this repository with add().
228 *
229 * This is a service method for the persistence manager to get all addedObjects
230 * added to the repository. Those are only objects *added*, not objects
231 * fetched from the underlying storage.
232 *
233 * @return Tx_Extbase_Persistence_ObjectStorage the objects
234 */
235 public function getAddedObjects() {
236 return $this->addedObjects;
237 }
238
239 /**
240 * Returns an Tx_Extbase_Persistence_ObjectStorage with objects remove()d from the repository
241 * that had been persisted to the storage layer before.
242 *
243 * @return Tx_Extbase_Persistence_ObjectStorage the objects
244 */
245 public function getRemovedObjects() {
246 return $this->removedObjects;
247 }
248
249 /**
250 * Returns all objects of this repository
251 *
252 * @return array An array of objects, empty if no objects found
253 * @api
254 */
255 public function findAll() {
256 $result = $this->createQuery()->execute();
257 return $result;
258 }
259
260 /**
261 * Returns the total number objects of this repository.
262 *
263 * @return integer The object count
264 * @api
265 */
266 public function countAll() {
267 return $this->createQuery()->execute()->count();
268 }
269
270 /**
271 * Removes all objects of this repository as if remove() was called for
272 * all of them.
273 *
274 * @return void
275 * @api
276 */
277 public function removeAll() {
278 $this->addedObjects = new Tx_Extbase_Persistence_ObjectStorage();
279 foreach ($this->findAll() as $object) {
280 $this->remove($object);
281 }
282 }
283
284 /**
285 * Finds an object matching the given identifier.
286 *
287 * @param int $uid The identifier of the object to find
288 * @return object The matching object if found, otherwise NULL
289 * @api
290 */
291 public function findByUid($uid) {
292 if ($this->identityMap->hasIdentifier($uid, $this->objectType)) {
293 $object = $this->identityMap->getObjectByIdentifier($uid, $this->objectType);
294 } else {
295 $query = $this->createQuery();
296 $query->getQuerySettings()->setRespectSysLanguage(FALSE);
297 $query->getQuerySettings()->setRespectStoragePage(FALSE);
298 $object = $query->matching($query->equals('uid', $uid))
299 ->execute()
300 ->getFirst();
301 if ($object !== NULL) {
302 $this->identityMap->registerObject($object, $uid);
303 }
304 }
305 return $object;
306 }
307
308 /**
309 * Sets the property names to order the result by per default.
310 * Expected like this:
311 * array(
312 * 'foo' => Tx_Extbase_Persistence_QueryInterface::ORDER_ASCENDING,
313 * 'bar' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING
314 * )
315 *
316 * @param array $defaultOrderings The property names to order by
317 * @return void
318 * @api
319 */
320 public function setDefaultOrderings(array $defaultOrderings) {
321 $this->defaultOrderings = $defaultOrderings;
322 }
323
324 /**
325 * Sets the default query settings to be used in this repository
326 *
327 * @param Tx_Extbase_Persistence_QuerySettingsInterface $defaultQuerySettings The query settings to be used by default
328 * @return void
329 * @api
330 */
331 public function setDefaultQuerySettings(Tx_Extbase_Persistence_QuerySettingsInterface $defaultQuerySettings) {
332 $this->defaultQuerySettings = $defaultQuerySettings;
333 }
334
335 /**
336 * Returns a query for objects of this repository
337 *
338 * @return Tx_Extbase_Persistence_QueryInterface
339 * @api
340 */
341 public function createQuery() {
342 $query = $this->queryFactory->create($this->objectType);
343 if ($this->defaultOrderings !== array()) {
344 $query->setOrderings($this->defaultOrderings);
345 }
346 if ($this->defaultQuerySettings !== NULL) {
347 $query->setQuerySettings($this->defaultQuerySettings);
348 }
349 return $query;
350 }
351
352 /**
353 * Dispatches magic methods (findBy[Property]())
354 *
355 * @param string $methodName The name of the magic method
356 * @param string $arguments The arguments of the magic method
357 * @throws Tx_Extbase_Persistence_Exception_UnsupportedMethod
358 * @return void
359 * @api
360 */
361 public function __call($methodName, $arguments) {
362 if (substr($methodName, 0, 6) === 'findBy' && strlen($methodName) > 7) {
363 $propertyName = strtolower(substr(substr($methodName, 6), 0, 1) ) . substr(substr($methodName, 6), 1);
364 $query = $this->createQuery();
365 $result = $query->matching($query->equals($propertyName, $arguments[0]))
366 ->execute();
367 return $result;
368 } elseif (substr($methodName, 0, 9) === 'findOneBy' && strlen($methodName) > 10) {
369 $propertyName = strtolower(substr(substr($methodName, 9), 0, 1) ) . substr(substr($methodName, 9), 1);
370 $query = $this->createQuery();
371 $object = $query->matching($query->equals($propertyName, $arguments[0]))
372 ->setLimit(1)
373 ->execute()
374 ->getFirst();
375 return $object;
376 } elseif (substr($methodName, 0, 7) === 'countBy' && strlen($methodName) > 8) {
377 $propertyName = strtolower(substr(substr($methodName, 7), 0, 1) ) . substr(substr($methodName, 7), 1);
378 $query = $this->createQuery();
379 $result = $query->matching($query->equals($propertyName, $arguments[0]))
380 ->execute()
381 ->count();
382 return $result;
383 }
384 throw new Tx_Extbase_Persistence_Exception_UnsupportedMethod('The method "' . $methodName . '" is not supported by the repository.', 1233180480);
385 }
386
387 /**
388 * Returns the class name of this class.
389 *
390 * @return string Class name of the repository.
391 */
392 protected function getRepositoryClassName() {
393 return get_class($this);
394 }
395
396 }
397 ?>