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