[TASK] Extbase (Persistence): Removed PreparedQuery for now, as it is not used at...
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Persistence / Backend.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 * A persistence backend. This backend maps objects to the relational model of the storage backend.
30 * It persists all added, removed and changed objects.
31 *
32 * @package Extbase
33 * @subpackage Persistence
34 * @version $Id: Backend.php 2183 2009-04-24 14:28:37Z k-fish $
35 */
36 class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendInterface, t3lib_Singleton {
37
38 /**
39 * @var Tx_Extbase_Persistence_Session
40 */
41 protected $session;
42
43 /**
44 * @var Tx_Extbase_Persistence_ObjectStorage
45 */
46 protected $aggregateRootObjects;
47
48 /**
49 * @var Tx_Extbase_Persistence_IdentityMap
50 **/
51 protected $identityMap;
52
53 /**
54 * @var Tx_Extbase_Persistence_QOM_QueryObjectModelFactoryInterface
55 */
56 protected $QOMFactory;
57
58 /**
59 * @var Tx_Extbase_Persistence_ValueFactoryInterface
60 */
61 protected $valueFactory;
62
63 /**
64 * @var Tx_Extbase_Persistence_Storage_BackendInterface
65 */
66 protected $storageBackend;
67
68 /**
69 * @var Tx_Extbase_Persistence_DataMapper
70 */
71 protected $dataMapper;
72
73 /**
74 * The TYPO3 reference index object
75 *
76 * @var t3lib_refindex
77 **/
78 protected $referenceIndex;
79
80 /**
81 * Constructs the backend
82 *
83 * @param Tx_Extbase_Persistence_Session $session The persistence session used to persist data
84 */
85 public function __construct(Tx_Extbase_Persistence_Session $session, Tx_Extbase_Persistence_Storage_BackendInterface $storageBackend) {
86 $this->session = $session;
87 $this->storageBackend = $storageBackend;
88 $this->referenceIndex = t3lib_div::makeInstance('t3lib_refindex');
89 $this->aggregateRootObjects = new Tx_Extbase_Persistence_ObjectStorage();
90 $this->persistenceBackend = $GLOBALS['TYPO3_DB']; // FIXME This is just an intermediate solution
91 }
92
93 /**
94 * Injects the DataMapper to map nodes to objects
95 *
96 * @param Tx_Extbase_Persistence_Mapper_DataMapper $dataMapper
97 * @return void
98 */
99 public function injectDataMapper(Tx_Extbase_Persistence_Mapper_DataMapper $dataMapper) {
100 $this->dataMapper = $dataMapper;
101 }
102
103 /**
104 * Injects the identity map
105 *
106 * @param Tx_Extbase_Persistence_IdentityMap $identityMap
107 * @return void
108
109 */
110 public function injectIdentityMap(Tx_Extbase_Persistence_IdentityMap $identityMap) {
111 $this->identityMap = $identityMap;
112 }
113
114 /**
115 * Injects the QueryObjectModelFactory
116 *
117 * @param Tx_Extbase_Persistence_QOM_QueryObjectModelFactoryInterface $dataMapper
118 * @return void
119 */
120 public function injectQOMFactory(Tx_Extbase_Persistence_QOM_QueryObjectModelFactoryInterface $QOMFactory) {
121 $this->QOMFactory = $QOMFactory;
122 }
123
124 /**
125 * Injects the ValueFactory
126 *
127 * @param Tx_Extbase_Persistence_ValueFactoryInterface $valueFactory
128 * @return void
129 */
130 public function injectValueFactory(Tx_Extbase_Persistence_ValueFactoryInterface $valueFactory) {
131 $this->valueFactory = $valueFactory;
132 }
133
134 /**
135 * Returns the repository session
136 *
137 * @return Tx_Extbase_Persistence_Session
138 */
139 public function getSession() {
140 return $this->session;
141 }
142
143 /**
144 * Returns the Data Mapper
145 *
146 * @return Tx_Extbase_Persistence_Mapper_DataMapper
147 */
148 public function getDataMapper() {
149 return $this->dataMapper;
150 }
151
152 /**
153 * Returns the current QOM factory
154 *
155 * @return Tx_Extbase_Persistence_QOM_QueryObjectModelFactoryInterface
156 */
157 public function getQOMFactory() {
158 return $this->QOMFactory;
159 }
160
161 /**
162 * Returns the current value factory
163 *
164 * @return Tx_Extbase_Persistence_ValueFactoryInterface
165 */
166 public function getValueFactory() {
167 return $this->valueFactory;
168 }
169
170 /**
171 * Returns the current identityMap
172 *
173 * @return Tx_Extbase_Persistence_IdentityMap
174 */
175 public function getIdentityMap() {
176 return $this->identityMap;
177 }
178
179 /**
180 * Returns the (internal) identifier for the object, if it is known to the
181 * backend. Otherwise NULL is returned.
182 *
183 * @param object $object
184 * @return string The identifier for the object if it is known, or NULL
185 */
186 public function getIdentifierByObject($object) {
187 if ($this->identityMap->hasObject($object)) {
188 return $this->identityMap->getIdentifierByObject($object);
189 } else {
190 return NULL;
191 }
192 }
193
194 /**
195 * Checks if the given object has ever been persisted.
196 *
197 * @param object $object The object to check
198 * @return boolean TRUE if the object is new, FALSE if the object exists in the repository
199 */
200 public function isNewObject($object) {
201 return ($this->getIdentifierByObject($object) === NULL);
202 }
203
204 /**
205 * Replaces the given object by the second object.
206 *
207 * This method will unregister the existing object at the identity map and
208 * register the new object instead. The existing object must therefore
209 * already be registered at the identity map which is the case for all
210 * reconstituted objects.
211 *
212 * The new object will be identified by the uid which formerly belonged
213 * to the existing object. The existing object looses its uid.
214 *
215 * @param object $existingObject The existing object
216 * @param object $newObject The new object
217 * @return void
218 */
219 public function replaceObject($existingObject, $newObject) {
220 $existingUid = $this->getIdentifierByObject($existingObject);
221 if ($existingUid === NULL) throw new Tx_Extbase_Persistence_Exception_UnknownObject('The given object is unknown to this persistence backend.', 1238070163);
222
223 $this->identityMap->unregisterObject($existingObject);
224 $this->identityMap->registerObject($newObject, $existingUid);
225 }
226
227 /**
228 * Sets the aggregate root objects
229 *
230 * @param Tx_Extbase_Persistence_ObjectStorage $objects
231 * @return void
232 */
233 public function setAggregateRootObjects(Tx_Extbase_Persistence_ObjectStorage $objects) {
234 $this->aggregateRootObjects = $objects;
235 }
236
237 /**
238 * Sets the deleted objects
239 *
240 * @param Tx_Extbase_Persistence_ObjectStorage $objects
241 * @return void
242 */
243 public function setDeletedObjects(Tx_Extbase_Persistence_ObjectStorage $objects) {
244 $this->deletedObjects = $objects;
245 }
246
247 /**
248 * Commits the current persistence session.
249 *
250 * @return void
251 */
252 public function commit() {
253 $this->persistObjects();
254 $this->processDeletedObjects();
255 }
256
257 /**
258 * Traverse and persist all aggregate roots and their object graph.
259 *
260 * @return void
261 */
262 protected function persistObjects() {
263 foreach ($this->aggregateRootObjects as $object) {
264 $this->persistObject($object);
265 }
266 }
267
268 /**
269 * Persists an object (instert, update) and its related objects (instert, update, delete).
270 *
271 * @param Tx_Extbase_DomainObject_DomainObjectInterface $object The object to be inserted
272 * @param Tx_Extbase_DomainObject_DomainObjectInterface $parentObject The parent object
273 * @param string $parentPropertyName The name of the property the object is stored in
274 * @return void
275 */
276 protected function persistObject(Tx_Extbase_DomainObject_DomainObjectInterface $object, $parentObject = NULL, $parentPropertyName = NULL) {
277 $row = array();
278 $queuedObjects = array();
279 $className = get_class($object);
280 $dataMap = $this->dataMapper->getDataMap($className);
281
282 if ($object instanceof Tx_Extbase_DomainObject_AbstractValueObject) {
283 $this->mapAlreadyPersistedValueObject($object);
284 }
285
286 $properties = $object->_getProperties();
287 // Fill up $row[$columnName] array with changed values which need to be stored
288 foreach ($properties as $propertyName => $propertyValue) {
289 if (!$dataMap->isPersistableProperty($propertyName) || ($propertyValue instanceof Tx_Extbase_Persistence_LazyLoadingProxy)) {
290 continue;
291 }
292
293 $columnMap = $dataMap->getColumnMap($propertyName);
294 if ($object->_isNew() || $object->_isDirty($propertyName)) {
295 if ($columnMap->isRelation()) {
296 $this->persistRelations($object, $propertyName, $propertyValue, $columnMap, $queuedObjects, $row);
297 } else {
298 // We have not a relation, this means it is a scalar (like a string or interger value) or an object
299 $row[$columnMap->getColumnName()] = $dataMap->convertPropertyValueToFieldValue($propertyValue);
300 }
301 }
302 } // end property iteration for loop
303
304 // The state of the Object has to be stored in a local variable because $object->_isNew() will return FALSE after
305 // the object was inserted. We need the initial state here.
306 $objectIsNew = $object->_isNew();
307 if ($objectIsNew === TRUE) {
308 $this->insertObject($object, $parentObject, $parentPropertyName, $row);
309 } elseif ($object->_isDirty()) {
310 $this->updateObject($object, $parentObject, $parentPropertyName, $row);
311 }
312
313 // SK: Where does $queueChildObjects come from? Do we need the code below?
314 $objectHasToBeUpdated = $this->processQueuedChildObjects($object, $queuedObjects, $row);
315 if ($objectHasToBeUpdated === TRUE) {
316 // TODO Check if this can be merged with the first update
317 $this->updateObject($object, $parentObject, $parentPropertyName, $row);
318 }
319
320 // SK: I need to check the code below more thoroughly
321 if ($parentObject instanceof Tx_Extbase_DomainObject_DomainObjectInterface && !empty($parentPropertyName)) {
322 $parentDataMap = $this->dataMapper->getDataMap(get_class($parentObject));
323 $parentColumnMap = $parentDataMap->getColumnMap($parentPropertyName);
324 if (($parentColumnMap->getTypeOfRelation() === Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY)) {
325 $this->insertRelationInRelationtable($object, $parentObject, $parentPropertyName);
326 }
327 }
328
329 $this->identityMap->registerObject($object, $object->getUid());
330 $object->_memorizeCleanState();
331 }
332
333 /**
334 * Persists a relation. Objects of a 1:n or m:n relation are queued and processed with the parent object. A 1:1 relation
335 * gets persisted immediately. Objects which were removed from the property were deleted immediately, too.
336 *
337 * @param Tx_Extbase_DomainObject_DomainObjectInterface $object The object to be inserted
338 * @param string $propertyName The name of the property the related objects are stored in
339 * @param mixed $propertyValue The property value (an array of Domain Objects, ObjectStorage holding Domain Objects or a Domain Object itself)
340 * @return void
341 */
342 protected function persistRelations(Tx_Extbase_DomainObject_DomainObjectInterface $object, $propertyName, $propertyValue, Tx_Extbase_Persistence_Mapper_ColumnMap $columnMap, &$queuedObjects, &$row) {
343 $columnName = $columnMap->getColumnName();
344 if (($columnMap->getTypeOfRelation() === Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_MANY) || ($columnMap->getTypeOfRelation() === Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY)) {
345 if (is_array($propertyValue) || $propertyValue instanceof ArrayAccess) {
346 foreach ($propertyValue as $relatedObject) {
347 $queuedObjects[$propertyName][] = $relatedObject;
348 }
349 $row[$columnName] = count($propertyValue); // Will be overwritten if the related objects are referenced by a comma separated list
350 foreach ($this->getDeletedChildObjects($object, $propertyName) as $deletedObject) {
351 $this->deleteObject($deletedObject, $object, $propertyName, TRUE, FALSE);
352 }
353 }
354 } elseif ($propertyValue instanceof Tx_Extbase_DomainObject_DomainObjectInterface) {
355 // TODO Handle Value Objects different
356 if ($propertyValue->_isNew() || $propertyValue->_isDirty()) {
357 $this->persistObject($propertyValue);
358 }
359 $row[$columnName] = $propertyValue->getUid();
360 }
361 }
362
363 /**
364 * Returns the deleted objects determined by a comparison of the clean property value
365 * with the actual property value.
366 *
367 * @param Tx_Extbase_DomainObject_AbstractEntity $object The object to be insterted in the storage
368 * @param string $parentPropertyName The name of the property
369 * @return array An array of deleted objects
370 */
371 protected function getDeletedChildObjects(Tx_Extbase_DomainObject_AbstractEntity $object, $propertyName) {
372 $deletedObjects = array();
373 if (!$object->_isNew()) {
374 $cleanProperties = $object->_getCleanProperties();
375 $cleanPropertyValue = $cleanProperties[$propertyName];
376 $propertyValue = $object->_getProperty($propertyName);
377 if ($cleanPropertyValue instanceof Tx_Extbase_Persistence_ObjectStorage) {
378 $cleanPropertyValue = $cleanPropertyValue->toArray();
379 }
380 if ($propertyValue instanceof Tx_Extbase_Persistence_ObjectStorage) {
381 $propertyValue = $propertyValue->toArray();
382 }
383 $deletedObjects = array_diff($cleanPropertyValue, $propertyValue);
384 }
385
386 return $deletedObjects;
387 }
388
389 /**
390 * This function processes the queued child objects to be persisted. The queue is build while looping over the
391 * collection of Domain Objects stored in a object property.
392 *
393 * @param Tx_Extbase_DomainObject_DomainObjectInterface $object The object holding the collection
394 * @param array $queuedObjects The queued child objects
395 * @param array $row The row to be inseted or updated in the database. Passed as reference.
396 * @return boolean TRUE if the object holding the collection has to be updated; otherwise FALSE
397 */
398 protected function processQueuedChildObjects(Tx_Extbase_DomainObject_DomainObjectInterface $object, array $queuedChildObjects, array &$row) {
399 $objectHasToBeUpdated = FALSE;
400 $className = get_class($object);
401 $dataMap = $this->dataMapper->getDataMap($className);
402 foreach ($queuedChildObjects as $propertyName => $childObjects) {
403 $childPidArray = array();
404 $columnMap = $dataMap->getColumnMap($propertyName);
405 foreach($childObjects as $childObject) {
406 $this->persistObject($childObject, $object, $propertyName);
407 if ($childObject instanceof Tx_Extbase_DomainObject_DomainObjectInterface) {
408 $childPidArray[] = (int)$childObject->getUid();
409 }
410 }
411 if ($columnMap->getParentKeyFieldName() === NULL) { // TRUE: We have to generate a comma separated list stored in the field
412 $row[$propertyName] = implode(',', $childPidArray);
413 $objectHasToBeUpdated = TRUE;
414 }
415 }
416 return $objectHasToBeUpdated;
417 }
418
419 /**
420 * Tests, if the given Value Object already exists in the storage backend. If so, it maps the uid
421 * to the given object.
422 *
423 * @param Tx_Extbase_DomainObject_AbstractValueObject $object The object to be tested
424 */
425 protected function mapAlreadyPersistedValueObject(Tx_Extbase_DomainObject_AbstractValueObject $object) {
426 $dataMap = $this->dataMapper->getDataMap(get_class($object));
427 $properties = $object->_getProperties();
428 $result = $this->storageBackend->hasValueObject($properties, $dataMap);
429 if ($result !== FALSE) {
430 $object->_setProperty('uid', $result);
431 }
432 }
433
434 /**
435 * Inserts an object in the storage
436 *
437 * @param Tx_Extbase_DomainObject_DomainObjectInterface $object The object to be insterted in the storage
438 * @param Tx_Extbase_DomainObject_AbstractEntity|NULL $parentObject The parent object (if any)
439 * @param string|NULL $parentPropertyName The name of the property
440 * @param array $row The $row
441 */
442 protected function insertObject(Tx_Extbase_DomainObject_DomainObjectInterface $object, Tx_Extbase_DomainObject_AbstractEntity $parentObject = NULL, $parentPropertyName = NULL, array &$row) {
443 $className = get_class($object);
444 $dataMap = $this->dataMapper->getDataMap($className);
445 $tableName = $dataMap->getTableName();
446 $this->addCommonFieldsToRow($object, $parentObject, $parentPropertyName, $row);
447 $uid = $this->storageBackend->addRow(
448 $tableName,
449 $row
450 );
451 $object->_setProperty('uid', $uid);
452 $this->referenceIndex->updateRefIndexTable($tableName, $uid);
453 }
454
455 /**
456 * Inserts mm-relation into a relation table
457 *
458 * @param Tx_Extbase_DomainObject_DomainObjectInterface $relatedObject The related object
459 * @param Tx_Extbase_DomainObject_DomainObjectInterface $parentObject The parent object
460 * @param string $parentPropertyName The name of the parent object's property where the related objects are stored in
461 * @return void
462 */
463 protected function insertRelationInRelationtable(Tx_Extbase_DomainObject_DomainObjectInterface $relatedObject, Tx_Extbase_DomainObject_DomainObjectInterface $parentObject, $parentPropertyName) {
464 $dataMap = $this->dataMapper->getDataMap(get_class($parentObject));
465 $columnMap = $dataMap->getColumnMap($parentPropertyName);
466 $row = array(
467 $columnMap->getParentKeyFieldName() => (int)$parentObject->getUid(),
468 $columnMap->getChildKeyFieldName() => (int)$relatedObject->getUid(),
469 'tablenames' => $columnMap->getChildTableName(),
470 'sorting' => 9999 // TODO sorting of mm table items
471 );
472 $res = $this->storageBackend->addRow(
473 $columnMap->getRelationTableName(),
474 $row,
475 TRUE);
476 return $res;
477 }
478
479 /**
480 * Updates a given object in the storage
481 *
482 * @param Tx_Extbase_DomainObject_DomainObjectInterface $object The object to be insterted in the storage
483 * @param Tx_Extbase_DomainObject_AbstractEntity|NULL $parentObject The parent object (if any)
484 * @param string|NULL $parentPropertyName The name of the property
485 * @param array $row The $row
486 */
487 protected function updateObject(Tx_Extbase_DomainObject_DomainObjectInterface $object, $parentObject = NULL, $parentPropertyName = NULL, array &$row) {
488 $className = get_class($object);
489 $dataMap = $this->dataMapper->getDataMap($className);
490 $tableName = $dataMap->getTableName();
491 $this->addCommonFieldsToRow($object, $parentObject, $parentPropertyName, $row);
492 $uid = $object->getUid();
493 $row['uid'] = $uid;
494 $res = $this->storageBackend->updateRow(
495 $tableName,
496 $row
497 );
498 $this->referenceIndex->updateRefIndexTable($tableName, $uid);
499 return $res;
500 }
501
502 /**
503 * Returns a table row to be inserted or updated in the database
504 *
505 * @param Tx_Extbase_Persistence_Mapper_DataMap $dataMap The appropriate data map representing a database table
506 * @param array $properties The properties of the object
507 * @return array A single row to be inserted in the database
508 */
509 protected function addCommonFieldsToRow(Tx_Extbase_DomainObject_DomainObjectInterface $object, $parentObject = NULL, $parentPropertyName = NULL, array &$row) {
510 $className = get_class($object);
511 $dataMap = $this->dataMapper->getDataMap($className);
512 if ($dataMap->hasCreationDateColumn() && $object->_isNew()) {
513 $row[$dataMap->getCreationDateColumnName()] = $GLOBALS['EXEC_TIME'];
514 }
515 if ($dataMap->hasTimestampColumn()) {
516 $row[$dataMap->getTimestampColumnName()] = $GLOBALS['EXEC_TIME'];
517 }
518
519 if ($object->_isNew() && $dataMap->hasPidColumn() && !isset($row['pid'])) {
520 $row['pid'] = $this->determineStoragePageIdForNewRecord($object);
521 }
522
523 if ($parentObject instanceof Tx_Extbase_DomainObject_DomainObjectInterface && !empty($parentPropertyName)) {
524 $parentDataMap = $this->dataMapper->getDataMap(get_class($parentObject));
525 $parentColumnMap = $parentDataMap->getColumnMap($parentPropertyName);
526 // FIXME This is a hacky solution
527 if ($parentColumnMap->getTypeOfRelation() !== Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
528 $parentKeyFieldName = $parentColumnMap->getParentKeyFieldName();
529 if ($parentKeyFieldName !== NULL) {
530 $row[$parentKeyFieldName] = $parentObject->getUid();
531 }
532 $parentTableFieldName = $parentColumnMap->getParentTableFieldName();
533 if ($parentTableFieldName !== NULL) {
534 $row[$parentTableFieldName] = $parentDataMap->getTableName();
535 }
536 }
537 }
538 }
539
540 /**
541 * Determine the storage page ID for a given NEW record
542 *
543 * This does the following:
544 * - If there is a TypoScript configuration "classes.CLASSNAME.newRecordStoragePid", that is used to store new records.
545 * - If there is no such TypoScript configuration, it uses the first value of The "storagePid" taken for reading records.
546 *
547 * @param Tx_Extbase_DomainObject_DomainObjectInterface $object
548 * @return int the storage Page ID where the object should be stored
549 */
550 protected function determineStoragePageIdForNewRecord(Tx_Extbase_DomainObject_DomainObjectInterface $object) {
551 $className = get_class($object);
552 $extbaseSettings = Tx_Extbase_Dispatcher::getSettings();
553
554 if (isset($extbaseSettings['classes'][$className]) && !empty($extbaseSettings['classes'][$className]['newRecordStoragePid'])) {
555 return (int)$extbaseSettings['classes'][$className]['newRecordStoragePid'];
556 } else {
557 $storagePidList = t3lib_div::intExplode(',', $extbaseSettings['storagePid']);
558 return (int) $storagePidList[0];
559 }
560 }
561
562 /**
563 * Iterate over deleted aggregate root objects and process them
564 *
565 * @return void
566 */
567 protected function processDeletedObjects() {
568 foreach ($this->deletedObjects as $object) {
569 $this->deleteObject($object);
570 $this->identityMap->unregisterObject($object);
571 }
572 $this->deletedObjects = new Tx_Extbase_Persistence_ObjectStorage();
573 }
574
575 /**
576 * Deletes an object, it's 1:n related objects, and the m:n relations in relation tables (but not the m:n related objects!)
577 *
578 * @param Tx_Extbase_DomainObject_DomainObjectInterface $object The object to be insterted in the storage
579 * @param Tx_Extbase_DomainObject_AbstractEntity|NULL $parentObject The parent object (if any)
580 * @param string|NULL $parentPropertyName The name of the property
581 * @param bool $markAsDeleted Shold we only mark the row as deleted instead of deleting (TRUE by default)?
582 * @return void
583 */
584 protected function deleteObject(Tx_Extbase_DomainObject_DomainObjectInterface $object, $parentObject = NULL, $parentPropertyName = NULL, $markAsDeleted = TRUE) {
585 // TODO Implement recursive deletions
586 $dataMap = $this->dataMapper->getDataMap(get_class($object));
587 $tableName = $dataMap->getTableName();
588 if (($markAsDeleted === TRUE) && $dataMap->hasDeletedColumn()) {
589 $deletedColumnName = $dataMap->getDeletedColumnName();
590 $res = $this->storageBackend->updateRow(
591 $tableName,
592 array(
593 'uid' => $object->getUid(),
594 $deletedColumnName => 1
595 )
596 );
597 } else {
598 $res = $this->storageBackend->removeRow(
599 $tableName,
600 $object->getUid()
601 );
602 }
603 $this->referenceIndex->updateRefIndexTable($tableName, $uid);
604 }
605
606 /**
607 * Delegates the call to the Data Map.
608 * Returns TRUE if the property is persistable (configured in $TCA)
609 *
610 * @param string $className The property name
611 * @param string $propertyName The property name
612 * @return boolean TRUE if the property is persistable (configured in $TCA)
613 */
614 public function isPersistableProperty($className, $propertyName) {
615 $dataMap = $this->dataMapper->getDataMap($className);
616 return $dataMap->isPersistableProperty($propertyName);
617 }
618
619 }
620
621 ?>