[!!!] Extbase: Reintegrating branch "dispatcher" to trunk. Resolves: #10605
[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 string
69 */
70 protected $objectType;
71
72 /**
73 * Constructs a new Repository
74 *
75 * @param Tx_Extbase_Object_ObjectManagerInterface $objectManager
76 */
77 public function __construct(Tx_Extbase_Object_ObjectManagerInterface $objectManager = NULL) {
78 $this->addedObjects = new Tx_Extbase_Persistence_ObjectStorage();
79 $this->removedObjects = new Tx_Extbase_Persistence_ObjectStorage();
80 $this->objectType = str_replace(array('_Repository_', 'Repository'), array('_Model_', ''), $this->getRepositoryClassName());
81
82 if ($objectManager === NULL) {
83 // Legacy creation, in case the object manager is NOT injected
84 // If ObjectManager IS there, then all properties are automatically injected
85 $objectManager = t3lib_div::makeInstance('Tx_Extbase_Object_ObjectManager');
86 $this->injectIdentityMap($objectManager->get('Tx_Extbase_Persistence_IdentityMap'));
87 $this->injectQueryFactory($objectManager->get('Tx_Extbase_Persistence_QueryFactory'));
88 $this->injectPersistenceManager($objectManager->get('Tx_Extbase_Persistence_Manager'));
89 }
90 }
91
92 /**
93 * @param Tx_Extbase_Persistence_IdentityMap $identityMap
94 * @return void
95 */
96 public function injectIdentityMap(Tx_Extbase_Persistence_IdentityMap $identityMap) {
97 $this->identityMap = $identityMap;
98 }
99
100 /**
101 * @param Tx_Extbase_Persistence_QueryFactory $queryFactory
102 * @return void
103 */
104 public function injectQueryFactory(Tx_Extbase_Persistence_QueryFactory $queryFactory) {
105 $this->queryFactory = $queryFactory;
106 }
107
108 /**
109 * @param Tx_Extbase_Persistence_Manager $persistenceManager
110 * @return void
111 */
112 public function injectPersistenceManager(Tx_Extbase_Persistence_Manager $persistenceManager) {
113 $this->persistenceManager = $persistenceManager;
114 $this->persistenceManager->registerRepositoryClassName($this->getRepositoryClassName());
115 }
116
117 /**
118 * Adds an object to this repository
119 *
120 * @param object $object The object to add
121 * @return void
122 * @api
123 */
124 public function add($object) {
125 if (!($object instanceof $this->objectType)) {
126 throw new Tx_Extbase_Persistence_Exception_IllegalObjectType('The object given to add() was not of the type (' . $this->objectType . ') this repository manages.', 1248363335);
127 }
128
129 $this->addedObjects->attach($object);
130 $this->removedObjects->detach($object);
131 }
132
133 /**
134 * Removes an object from this repository.
135 *
136 * @param object $object The object to remove
137 * @return void
138 * @api
139 */
140 public function remove($object) {
141 if (!($object instanceof $this->objectType)) {
142 throw new Tx_Extbase_Persistence_Exception_IllegalObjectType('The object given to remove() was not of the type (' . $this->objectType . ') this repository manages.', 1248363335);
143 }
144
145 if ($this->addedObjects->contains($object)) {
146 $this->addedObjects->detach($object);
147 } else {
148 $this->removedObjects->attach($object);
149 }
150 }
151
152 /**
153 * Replaces an object by another.
154 *
155 * @param object $existingObject The existing object
156 * @param object $newObject The new object
157 * return void
158 * @api
159 */
160 public function replace($existingObject, $newObject) {
161 if (!($existingObject instanceof $this->objectType)) {
162 throw new Tx_Extbase_Persistence_Exception_IllegalObjectType('The existing object given to replace was not of the type (' . $this->objectType . ') this repository manages.', 1248363434);
163 }
164 if (!($newObject instanceof $this->objectType)) {
165 throw new Tx_Extbase_Persistence_Exception_IllegalObjectType('The new object given to replace was not of the type (' . $this->objectType . ') this repository manages.', 1248363439);
166 }
167
168 $backend = $this->persistenceManager->getBackend();
169 $session = $this->persistenceManager->getSession();
170 $uuid = $backend->getIdentifierByObject($existingObject);
171 if ($uuid !== NULL) {
172 $backend->replaceObject($existingObject, $newObject);
173 $session->unregisterReconstitutedObject($existingObject);
174 $session->registerReconstitutedObject($newObject);
175
176 if ($this->removedObjects->contains($existingObject)) {
177 $this->removedObjects->detach($existingObject);
178 $this->removedObjects->attach($newObject);
179 }
180 } elseif ($this->addedObjects->contains($existingObject)) {
181 $this->addedObjects->detach($existingObject);
182 $this->addedObjects->attach($newObject);
183 } else {
184 throw new Tx_Extbase_Persistence_Exception_UnknownObject('The "existing object" is unknown to the persistence backend.', 1238068475);
185 }
186
187 }
188
189 /**
190 * Replaces an existing object with the same identifier by the given object
191 *
192 * @param object $modifiedObject The modified object
193 * @api
194 */
195 public function update($modifiedObject) {
196 if (!($modifiedObject instanceof $this->objectType)) {
197 throw new Tx_Extbase_Persistence_Exception_IllegalObjectType('The modified object given to update() was not of the type (' . $this->objectType . ') this repository manages.', 1249479625);
198 }
199
200 $uid = $modifiedObject->getUid();
201 if ($uid !== NULL) {
202 $existingObject = $this->findByUid($uid);
203 $this->replace($existingObject, $modifiedObject);
204 } else {
205 throw new Tx_Extbase_Persistence_Exception_UnknownObject('The "modified object" is does not have an existing counterpart in this repository.', 1249479819);
206 }
207 }
208
209 /**
210 * Returns all addedObjects that have been added to this repository with add().
211 *
212 * This is a service method for the persistence manager to get all addedObjects
213 * added to the repository. Those are only objects *added*, not objects
214 * fetched from the underlying storage.
215 *
216 * @return Tx_Extbase_Persistence_ObjectStorage the objects
217 */
218 public function getAddedObjects() {
219 return $this->addedObjects;
220 }
221
222 /**
223 * Returns an Tx_Extbase_Persistence_ObjectStorage with objects remove()d from the repository
224 * that had been persisted to the storage layer before.
225 *
226 * @return Tx_Extbase_Persistence_ObjectStorage the objects
227 */
228 public function getRemovedObjects() {
229 return $this->removedObjects;
230 }
231
232 /**
233 * Returns all objects of this repository
234 *
235 * @return array An array of objects, empty if no objects found
236 * @api
237 */
238 public function findAll() {
239 $result = $this->createQuery()->execute();
240 return $result;
241 }
242
243 /**
244 * Returns the total number objects of this repository.
245 *
246 * @return integer The object count
247 * @api
248 */
249 public function countAll() {
250 return $this->createQuery()->count();
251 }
252
253 /**
254 * Removes all objects of this repository as if remove() was called for
255 * all of them.
256 *
257 * @return void
258 * @api
259 */
260 public function removeAll() {
261 $this->addedObjects = new Tx_Extbase_Persistence_ObjectStorage();
262 foreach ($this->findAll() as $object) {
263 $this->remove($object);
264 }
265 }
266
267 /**
268 * Finds an object matching the given identifier.
269 *
270 * @param int $uid The identifier of the object to find
271 * @return object The matching object if found, otherwise NULL
272 * @api
273 */
274 public function findByUid($uid) {
275 if ($this->identityMap->hasIdentifier($uid, $this->objectType)) {
276 $object = $this->identityMap->getObjectByIdentifier($uid, $this->objectType);
277 } else {
278 $query = $this->createQuery();
279 $query->getQuerySettings()->setRespectSysLanguage(FALSE);
280 $query->getQuerySettings()->setRespectStoragePage(FALSE);
281 $result = $query->matching($query->equals('uid', $uid))->execute();
282 $object = NULL;
283 if (count($result) > 0) {
284 $object = current($result);
285 $this->identityMap->registerObject($object, $uid);
286 }
287 }
288 return $object;
289 }
290
291 /**
292 * Returns a query for objects of this repository
293 *
294 * @return Tx_Extbase_Persistence_QueryInterface
295 * @api
296 */
297 public function createQuery() {
298 return $this->queryFactory->create($this->objectType);
299 }
300
301 /**
302 * Dispatches magic methods (findBy[Property]())
303 *
304 * @param string $methodName The name of the magic method
305 * @param string $arguments The arguments of the magic method
306 * @throws Tx_Extbase_Persistence_Exception_UnsupportedMethod
307 * @return void
308 * @api
309 */
310 public function __call($methodName, $arguments) {
311 if (substr($methodName, 0, 6) === 'findBy' && strlen($methodName) > 7) {
312 $propertyName = strtolower(substr(substr($methodName, 6), 0, 1) ) . substr(substr($methodName, 6), 1);
313 $query = $this->createQuery();
314 $result = $query->matching($query->equals($propertyName, $arguments[0]))
315 ->execute();
316 return $result;
317 } elseif (substr($methodName, 0, 9) === 'findOneBy' && strlen($methodName) > 10) {
318 $propertyName = strtolower(substr(substr($methodName, 9), 0, 1) ) . substr(substr($methodName, 9), 1);
319 $query = $this->createQuery();
320 $result = $query->matching($query->equals($propertyName, $arguments[0]))
321 ->setLimit(1)
322 ->execute();
323 $object = NULL;
324 if (count($result) > 0) {
325 $object = current($result);
326 }
327 return $object;
328 } elseif (substr($methodName, 0, 7) === 'countBy' && strlen($methodName) > 8) {
329 $propertyName = strtolower(substr(substr($methodName, 7), 0, 1) ) . substr(substr($methodName, 7), 1);
330 $query = $this->createQuery();
331 $result = $query->matching($query->equals($propertyName, $arguments[0]))
332 ->count();
333 return $result;
334 }
335 throw new Tx_Extbase_Persistence_Exception_UnsupportedMethod('The method "' . $methodName . '" is not supported by the repository.', 1233180480);
336 }
337
338 /**
339 * Returns the class name of this class.
340 *
341 * @return string Class name of the repository.
342 */
343 protected function getRepositoryClassName() {
344 return get_class($this);
345 }
346
347 }
348 ?>