‪TYPO3CMS  11.5
Backend.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
18 use Psr\EventDispatcher\EventDispatcherInterface;
42 
49 {
53  protected ‪$session;
54 
58  protected ‪$persistenceManager;
59 
63  protected ‪$aggregateRootObjects;
64 
69 
73  protected ‪$changedEntities;
74 
79 
83  protected ‪$reflectionService;
84 
88  protected ‪$storageBackend;
89 
93  protected ‪$dataMapFactory;
94 
100  protected ‪$referenceIndex;
101 
105  protected ‪$configurationManager;
106 
110  protected ‪$signalSlotDispatcher;
111 
115  protected ‪$eventDispatcher;
116 
127  public function ‪__construct(
131  \‪TYPO3\CMS\‪Extbase\Persistence\Generic\Storage\‪BackendInterface ‪$storageBackend,
133  EventDispatcherInterface ‪$eventDispatcher
134  ) {
135  $this->configurationManager = ‪$configurationManager;
136  $this->session = ‪$session;
137  $this->reflectionService = ‪$reflectionService;
138  $this->storageBackend = ‪$storageBackend;
139  $this->dataMapFactory = ‪$dataMapFactory;
140  $this->eventDispatcher = ‪$eventDispatcher;
141 
142  $this->referenceIndex = GeneralUtility::makeInstance(ReferenceIndex::class);
143  $this->aggregateRootObjects = new ‪ObjectStorage();
144  $this->deletedEntities = new ‪ObjectStorage();
145  $this->changedEntities = new ‪ObjectStorage();
146  }
147 
152  {
153  $this->persistenceManager = ‪$persistenceManager;
154  }
155 
162  public function ‪getObjectCountByQuery(‪QueryInterface $query)
163  {
164  return $this->storageBackend->getObjectCountByQuery($query);
165  }
166 
173  public function ‪getObjectDataByQuery(QueryInterface $query)
174  {
175  $event = new ModifyQueryBeforeFetchingObjectDataEvent($query);
176  $this->eventDispatcher->dispatch($event);
177  $query = $event->getQuery();
178  $result = $this->storageBackend->getObjectDataByQuery($query);
179  $event = new ‪ModifyResultAfterFetchingObjectDataEvent($query, $result);
180  $this->eventDispatcher->dispatch($event);
181  return $event->getResult();
182  }
183 
191  public function ‪getIdentifierByObject($object)
192  {
193  if ($object instanceof ‪LazyLoadingProxy) {
194  $object = $object->_loadRealInstance();
195  }
196 
197  return is_object($object) ? $this->session->getIdentifierByObject($object) : null;
198  }
199 
208  public function ‪getObjectByIdentifier($identifier, $className)
209  {
210  if ($this->session->hasIdentifier($identifier, $className)) {
211  return $this->session->getObjectByIdentifier($identifier, $className);
212  }
213  $query = $this->persistenceManager->createQueryForType($className);
214  $query->getQuerySettings()->setRespectStoragePage(false);
215  $query->getQuerySettings()->setRespectSysLanguage(false);
216  $query->getQuerySettings()->setLanguageOverlayMode(true);
217  return $query->matching($query->equals('uid', $identifier))->execute()->getFirst();
218  }
219 
226  public function ‪isNewObject($object)
227  {
228  return $this->‪getIdentifierByObject($object) === null;
229  }
230 
236  public function ‪setAggregateRootObjects(‪ObjectStorage $objects)
237  {
238  $this->aggregateRootObjects = $objects;
239  }
240 
246  public function ‪setChangedEntities(ObjectStorage $entities)
247  {
248  $this->changedEntities = $entities;
249  }
250 
256  public function ‪setDeletedEntities(ObjectStorage $entities)
257  {
258  $this->deletedEntities = $entities;
259  }
260 
264  public function ‪commit()
265  {
266  $this->‪persistObjects();
267  $this->‪processDeletedObjects();
268  }
269 
273  protected function ‪persistObjects()
274  {
275  $this->visitedDuringPersistence = new ‪ObjectStorage();
276  foreach ($this->aggregateRootObjects as $object) {
278  if ($object->_isNew()) {
279  $this->‪insertObject($object);
280  }
281  $this->‪persistObject($object);
282  }
283  foreach ($this->changedEntities as $object) {
284  $this->‪persistObject($object);
285  }
286  }
287 
293  protected function ‪persistObject(DomainObjectInterface $object)
294  {
295  if (isset($this->visitedDuringPersistence[$object])) {
296  return;
297  }
298  $row = [];
299  $queue = [];
300  $className = get_class($object);
301  $dataMap = $this->dataMapFactory->buildDataMap($className);
302  $classSchema = $this->reflectionService->getClassSchema($className);
303  foreach ($classSchema->getDomainObjectProperties() as $property) {
304  $propertyName = $property->getName();
305  if (!$dataMap->isPersistableProperty($propertyName)) {
306  continue;
307  }
308  $propertyValue = $object->_getProperty($propertyName);
309  if ($this->‪propertyValueIsLazyLoaded($propertyValue)) {
310  continue;
311  }
312  $columnMap = $dataMap->getColumnMap($propertyName);
313  if ($propertyValue instanceof ObjectStorage) {
314  $cleanProperty = $object->_getCleanProperty($propertyName);
315  // objectstorage needs to be persisted if the object is new, the objectstorage is dirty, meaning it has
316  // been changed after initial build, or an empty objectstorage is present and the cleanstate objectstorage
317  // has childelements, meaning all elements should been removed from the objectstorage
318  if ($object->_isNew() || $propertyValue->_isDirty() || ($propertyValue->count() === 0 && $cleanProperty && $cleanProperty->count() > 0)) {
319  $this->‪persistObjectStorage($propertyValue, $object, $propertyName, $row);
320  $propertyValue->_memorizeCleanState();
321  }
322  foreach ($propertyValue as $containedObject) {
323  if ($containedObject instanceof DomainObjectInterface) {
324  $queue[] = $containedObject;
325  }
326  }
327  } elseif ($propertyValue instanceof DomainObjectInterface
328  && $object instanceof ObjectMonitoringInterface) {
329  if ($object->_isDirty($propertyName)) {
330  if ($propertyValue->_isNew()) {
331  $this->‪insertObject($propertyValue, $object, $propertyName);
332  }
333  $row[$columnMap->getColumnName()] = $this->‪getPlainValue($propertyValue);
334  }
335  $queue[] = $propertyValue;
336  } elseif ($object->_isNew() || $object->_isDirty($propertyName)) {
337  $row[$columnMap->getColumnName()] = $this->‪getPlainValue($propertyValue, $columnMap);
338  }
339  }
340  if (!empty($row)) {
341  $this->‪updateObject($object, $row);
342  $object->_memorizeCleanState();
343  }
344  $this->visitedDuringPersistence[$object] = $object->getUid();
345  foreach ($queue as $queuedObject) {
346  $this->‪persistObject($queuedObject);
347  }
348  $this->eventDispatcher->dispatch(new ‪EntityPersistedEvent($object));
349  }
350 
357  protected function ‪propertyValueIsLazyLoaded($propertyValue)
358  {
359  if ($propertyValue instanceof LazyLoadingProxy) {
360  return true;
361  }
362  if ($propertyValue instanceof LazyObjectStorage) {
363  if ($propertyValue->isInitialized() === false) {
364  return true;
365  }
366  }
367  return false;
368  }
369 
381  protected function ‪persistObjectStorage(‪ObjectStorage $objectStorage, ‪DomainObjectInterface $parentObject, $propertyName, array &$row)
382  {
383  $className = get_class($parentObject);
384  $dataMapper = GeneralUtility::makeInstance(DataMapper::class);
385  $columnMap = $this->dataMapFactory->buildDataMap($className)->getColumnMap($propertyName);
386  $property = $this->reflectionService->getClassSchema($className)->getProperty($propertyName);
387  foreach ($this->‪getRemovedChildObjects($parentObject, $propertyName) as $removedObject) {
388  $this->‪detachObjectFromParentObject($removedObject, $parentObject, $propertyName);
389  if ($columnMap->getTypeOfRelation() === ‪ColumnMap::RELATION_HAS_MANY && $property->getCascadeValue() === 'remove') {
390  $this->‪removeEntity($removedObject);
391  }
392  }
393 
394  $currentUids = [];
395  $sortingPosition = 1;
396  $updateSortingOfFollowing = false;
397 
398  foreach ($objectStorage as $object) {
400  if (empty($currentUids)) {
401  $sortingPosition = 1;
402  } else {
403  $sortingPosition++;
404  }
405  $cleanProperty = $parentObject->‪_getCleanProperty($propertyName);
406  if ($object->_isNew()) {
407  $this->‪insertObject($object);
408  $this->‪attachObjectToParentObject($object, $parentObject, $propertyName, $sortingPosition);
409  // if a new object is inserted, all objects after this need to have their sorting updated
410  $updateSortingOfFollowing = true;
411  } elseif ($cleanProperty === null || $cleanProperty->getPosition($object) === null) {
412  // if parent object is new then it doesn't have cleanProperty yet; before attaching object it's clean position is null
413  $this->‪attachObjectToParentObject($object, $parentObject, $propertyName, $sortingPosition);
414  // if a relation is dirty (speaking the same object is removed and added again at a different position), all objects after this needs to be updated the sorting
415  $updateSortingOfFollowing = true;
416  } elseif ($objectStorage->‪isRelationDirty($object) || $cleanProperty->getPosition($object) !== $objectStorage->‪getPosition($object)) {
417  $this->‪updateRelationOfObjectToParentObject($object, $parentObject, $propertyName, $sortingPosition);
418  $updateSortingOfFollowing = true;
419  } elseif ($updateSortingOfFollowing) {
420  if ($sortingPosition > $objectStorage->‪getPosition($object)) {
421  $this->‪updateRelationOfObjectToParentObject($object, $parentObject, $propertyName, $sortingPosition);
422  } else {
423  $sortingPosition = $objectStorage->‪getPosition($object);
424  }
425  }
426  $currentUids[] = $object->getUid();
427  }
428 
429  if ($columnMap->getParentKeyFieldName() === null) {
430  $row[$columnMap->getColumnName()] = implode(',', $currentUids);
431  } else {
432  $row[$columnMap->getColumnName()] = $dataMapper->countRelated($parentObject, $propertyName);
433  }
434  }
435 
444  protected function ‪getRemovedChildObjects(DomainObjectInterface $object, $propertyName)
445  {
446  $removedObjects = [];
447  $cleanPropertyValue = $object->_getCleanProperty($propertyName);
448  if (is_array($cleanPropertyValue) || $cleanPropertyValue instanceof \Iterator) {
449  $propertyValue = $object->_getProperty($propertyName);
450  foreach ($cleanPropertyValue as $containedObject) {
451  if (!$propertyValue->contains($containedObject)) {
452  $removedObjects[] = $containedObject;
453  }
454  }
455  }
456  return $removedObjects;
457  }
458 
467  protected function ‪attachObjectToParentObject(DomainObjectInterface $object, DomainObjectInterface $parentObject, $parentPropertyName, $sortingPosition = 0)
468  {
469  $parentDataMap = $this->dataMapFactory->buildDataMap(get_class($parentObject));
470 
471  $parentColumnMap = $parentDataMap->getColumnMap($parentPropertyName);
472  if ($parentColumnMap->getTypeOfRelation() === ‪ColumnMap::RELATION_HAS_MANY) {
473  $this->‪attachObjectToParentObjectRelationHasMany($object, $parentObject, $parentPropertyName, $sortingPosition);
474  } elseif ($parentColumnMap->getTypeOfRelation() === ‪ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
475  $this->‪insertRelationInRelationtable($object, $parentObject, $parentPropertyName, $sortingPosition);
476  }
477  }
478 
487  protected function ‪updateRelationOfObjectToParentObject(DomainObjectInterface $object, DomainObjectInterface $parentObject, $parentPropertyName, $sortingPosition = 0)
488  {
489  $parentDataMap = $this->dataMapFactory->buildDataMap(get_class($parentObject));
490  $parentColumnMap = $parentDataMap->getColumnMap($parentPropertyName);
491  if ($parentColumnMap->getTypeOfRelation() === ‪ColumnMap::RELATION_HAS_MANY) {
492  $this->‪attachObjectToParentObjectRelationHasMany($object, $parentObject, $parentPropertyName, $sortingPosition);
493  } elseif ($parentColumnMap->getTypeOfRelation() === ‪ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
494  $this->‪updateRelationInRelationTable($object, $parentObject, $parentPropertyName, $sortingPosition);
495  }
496  }
497 
507  protected function ‪attachObjectToParentObjectRelationHasMany(‪DomainObjectInterface $object, ‪DomainObjectInterface $parentObject, $parentPropertyName, $sortingPosition = 0)
508  {
509  $parentDataMap = $this->dataMapFactory->buildDataMap(get_class($parentObject));
510  $parentColumnMap = $parentDataMap->getColumnMap($parentPropertyName);
511  if ($parentColumnMap->getTypeOfRelation() !== ‪ColumnMap::RELATION_HAS_MANY) {
512  throw new IllegalRelationTypeException(
513  'Parent column relation type is ' . $parentColumnMap->getTypeOfRelation() .
514  ' but should be ' . ‪ColumnMap::RELATION_HAS_MANY,
515  1345368105
516  );
517  }
518  $row = [];
519  $parentKeyFieldName = $parentColumnMap->getParentKeyFieldName();
520  if ($parentKeyFieldName !== null) {
521  $row[$parentKeyFieldName] = $parentObject->‪_getProperty('_localizedUid') ?: $parentObject->‪getUid();
522  $parentTableFieldName = $parentColumnMap->getParentTableFieldName();
523  if ($parentTableFieldName !== null) {
524  $row[$parentTableFieldName] = $parentDataMap->getTableName();
525  }
526  $relationTableMatchFields = $parentColumnMap->getRelationTableMatchFields();
527  if (is_array($relationTableMatchFields)) {
528  $row = array_merge($relationTableMatchFields, $row);
529  }
530  }
531  $childSortByFieldName = $parentColumnMap->getChildSortByFieldName();
532  if (!empty($childSortByFieldName)) {
533  $row[$childSortByFieldName] = $sortingPosition;
534  }
535  if (!empty($row)) {
536  $this->‪updateObject($object, $row);
537  }
538  }
539 
547  protected function ‪detachObjectFromParentObject(DomainObjectInterface $object, DomainObjectInterface $parentObject, $parentPropertyName)
548  {
549  $parentDataMap = $this->dataMapFactory->buildDataMap(get_class($parentObject));
550  $parentColumnMap = $parentDataMap->getColumnMap($parentPropertyName);
551  if ($parentColumnMap->getTypeOfRelation() === ‪ColumnMap::RELATION_HAS_MANY) {
552  $row = [];
553  $parentKeyFieldName = $parentColumnMap->getParentKeyFieldName();
554  if ($parentKeyFieldName !== null) {
555  $row[$parentKeyFieldName] = 0;
556  $parentTableFieldName = $parentColumnMap->getParentTableFieldName();
557  if ($parentTableFieldName !== null) {
558  $row[$parentTableFieldName] = '';
559  }
560  $relationTableMatchFields = $parentColumnMap->getRelationTableMatchFields();
561  if (is_array($relationTableMatchFields) && !empty($relationTableMatchFields)) {
562  $row = array_merge(array_fill_keys(array_keys($relationTableMatchFields), ''), $row);
563  }
564  }
565  $childSortByFieldName = $parentColumnMap->getChildSortByFieldName();
566  if (!empty($childSortByFieldName)) {
567  $row[$childSortByFieldName] = 0;
568  }
569  if (!empty($row)) {
570  $this->‪updateObject($object, $row);
571  }
572  } elseif ($parentColumnMap->getTypeOfRelation() === ‪ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
573  $this->‪deleteRelationFromRelationtable($object, $parentObject, $parentPropertyName);
574  }
575  }
576 
584  protected function ‪insertObject(DomainObjectInterface $object, DomainObjectInterface $parentObject = null, $parentPropertyName = '')
585  {
586  if ($object instanceof AbstractValueObject) {
587  $result = $this->‪getUidOfAlreadyPersistedValueObject($object);
588  if ($result !== null) {
589  $object->_setProperty('uid', $result);
590  return;
591  }
592  }
593  $className = get_class($object);
594  $dataMap = $this->dataMapFactory->buildDataMap($className);
595  $row = [];
596  $classSchema = $this->reflectionService->getClassSchema($className);
597  foreach ($classSchema->getDomainObjectProperties() as $property) {
598  $propertyName = $property->getName();
599  if (!$dataMap->isPersistableProperty($propertyName)) {
600  continue;
601  }
602  $propertyValue = $object->_getProperty($propertyName);
603  if ($this->‪propertyValueIsLazyLoaded($propertyValue)) {
604  continue;
605  }
606  $columnMap = $dataMap->getColumnMap($propertyName);
607  if ($columnMap->getTypeOfRelation() === ‪ColumnMap::RELATION_HAS_ONE) {
608  $row[$columnMap->getColumnName()] = 0;
609  } elseif ($columnMap->getTypeOfRelation() !== ‪ColumnMap::RELATION_NONE) {
610  if ($columnMap->getParentKeyFieldName() === null) {
611  // CSV type relation
612  $row[$columnMap->getColumnName()] = '';
613  } else {
614  // MM type relation
615  $row[$columnMap->getColumnName()] = 0;
616  }
617  } elseif ($propertyValue !== null) {
618  $row[$columnMap->getColumnName()] = $this->‪getPlainValue($propertyValue, $columnMap);
619  }
620  }
621  $this->‪addCommonFieldsToRow($object, $row);
622  if ($dataMap->getLanguageIdColumnName() !== null && $object->_getProperty('_languageUid') === null) {
623  $row[$dataMap->getLanguageIdColumnName()] = 0;
624  $object->_setProperty('_languageUid', 0);
625  }
626  if ($dataMap->getTranslationOriginColumnName() !== null) {
627  $row[$dataMap->getTranslationOriginColumnName()] = 0;
628  }
629  if ($dataMap->getTranslationOriginDiffSourceName() !== null) {
630  $row[$dataMap->getTranslationOriginDiffSourceName()] = '';
631  }
632  if ($parentObject !== null && $parentPropertyName) {
633  $parentColumnDataMap = $this->dataMapFactory->buildDataMap(get_class($parentObject))->getColumnMap($parentPropertyName);
634  $relationTableMatchFields = $parentColumnDataMap->getRelationTableMatchFields();
635  if (is_array($relationTableMatchFields)) {
636  $row = array_merge($relationTableMatchFields, $row);
637  }
638  if ($parentColumnDataMap->getParentKeyFieldName() !== null) {
639  $row[$parentColumnDataMap->getParentKeyFieldName()] = (int)$parentObject->getUid();
640  }
641  }
642  $uid = $this->storageBackend->addRow($dataMap->getTableName(), $row);
643  $object->_setProperty('uid', (int)$uid);
644  $object->setPid((int)$row['pid']);
645  if ((int)$uid >= 1) {
646  $this->eventDispatcher->dispatch(new EntityAddedToPersistenceEvent($object));
647  }
648  $frameworkConfiguration = $this->configurationManager->getConfiguration(‪ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
649  if (($frameworkConfiguration['persistence']['updateReferenceIndex'] ?? '') === '1') {
650  $this->referenceIndex->updateRefIndexTable($dataMap->getTableName(), $uid);
651  }
652  $this->session->registerObject($object, $uid);
653  if ((int)$uid >= 1) {
654  $this->eventDispatcher->dispatch(new ‪EntityFinalizedAfterPersistenceEvent($object));
655  }
656  }
657 
664  protected function ‪getUidOfAlreadyPersistedValueObject(AbstractValueObject $object)
665  {
666  return $this->storageBackend->getUidOfAlreadyPersistedValueObject($object);
667  }
668 
678  protected function ‪insertRelationInRelationtable(‪DomainObjectInterface $object, ‪DomainObjectInterface $parentObject, $propertyName, $sortingPosition = null)
679  {
680  $dataMap = $this->dataMapFactory->buildDataMap(get_class($parentObject));
681  $columnMap = $dataMap->getColumnMap($propertyName);
682  $parentUid = $parentObject->‪getUid();
683  if ($parentObject->‪_getProperty('_localizedUid') !== null) {
684  $parentUid = $parentObject->‪_getProperty('_localizedUid');
685  }
686  $row = [
687  $columnMap->getParentKeyFieldName() => (int)$parentUid,
688  $columnMap->getChildKeyFieldName() => (int)$object->‪getUid(),
689  $columnMap->getChildSortByFieldName() => $sortingPosition !== null ? (int)$sortingPosition : 0,
690  ];
691  $relationTableName = $columnMap->getRelationTableName();
692  if ($columnMap->getRelationTablePageIdColumnName() !== null) {
693  $row[$columnMap->getRelationTablePageIdColumnName()] = $this->‪determineStoragePageIdForNewRecord();
694  }
695  $relationTableMatchFields = $columnMap->getRelationTableMatchFields();
696  if (is_array($relationTableMatchFields)) {
697  $row = array_merge($relationTableMatchFields, $row);
698  }
699  $relationTableInsertFields = $columnMap->getRelationTableInsertFields();
700  if (is_array($relationTableInsertFields)) {
701  $row = array_merge($relationTableInsertFields, $row);
702  }
703  $res = $this->storageBackend->addRow($relationTableName, $row, true);
704  return $res;
705  }
706 
716  protected function ‪updateRelationInRelationTable(‪DomainObjectInterface $object, ‪DomainObjectInterface $parentObject, $propertyName, $sortingPosition = 0)
717  {
718  $dataMap = $this->dataMapFactory->buildDataMap(get_class($parentObject));
719  $columnMap = $dataMap->getColumnMap($propertyName);
720  $row = [
721  $columnMap->getParentKeyFieldName() => (int)$parentObject->‪getUid(),
722  $columnMap->getChildKeyFieldName() => (int)$object->‪getUid(),
723  $columnMap->getChildSortByFieldName() => (int)$sortingPosition,
724  ];
725  $relationTableName = $columnMap->getRelationTableName();
726  $relationTableMatchFields = $columnMap->getRelationTableMatchFields();
727  if (is_array($relationTableMatchFields)) {
728  $row = array_merge($relationTableMatchFields, $row);
729  }
730  $this->storageBackend->updateRelationTableRow(
731  $relationTableName,
732  $row
733  );
734  return true;
735  }
736 
744  protected function ‪deleteAllRelationsFromRelationtable(‪DomainObjectInterface $parentObject, $parentPropertyName)
745  {
746  $dataMap = $this->dataMapFactory->buildDataMap(get_class($parentObject));
747  $columnMap = $dataMap->getColumnMap($parentPropertyName);
748  $relationTableName = $columnMap->getRelationTableName();
749  $relationMatchFields = [
750  $columnMap->getParentKeyFieldName() => (int)$parentObject->‪getUid(),
751  ];
752  $relationTableMatchFields = $columnMap->getRelationTableMatchFields();
753  if (is_array($relationTableMatchFields)) {
754  $relationMatchFields = array_merge($relationTableMatchFields, $relationMatchFields);
755  }
756  $this->storageBackend->removeRow($relationTableName, $relationMatchFields, false);
757  return true;
758  }
759 
768  protected function ‪deleteRelationFromRelationtable(‪DomainObjectInterface $relatedObject, ‪DomainObjectInterface $parentObject, $parentPropertyName)
769  {
770  $dataMap = $this->dataMapFactory->buildDataMap(get_class($parentObject));
771  $columnMap = $dataMap->getColumnMap($parentPropertyName);
772  $relationTableName = $columnMap->getRelationTableName();
773  $relationMatchFields = [
774  $columnMap->getParentKeyFieldName() => (int)$parentObject->‪getUid(),
775  $columnMap->getChildKeyFieldName() => (int)$relatedObject->‪getUid(),
776  ];
777  $relationTableMatchFields = $columnMap->getRelationTableMatchFields();
778  if (is_array($relationTableMatchFields)) {
779  $relationMatchFields = array_merge($relationTableMatchFields, $relationMatchFields);
780  }
781  $this->storageBackend->removeRow($relationTableName, $relationMatchFields, false);
782  return true;
783  }
784 
792  protected function ‪updateObject(‪DomainObjectInterface $object, array $row)
793  {
794  $dataMap = $this->dataMapFactory->buildDataMap(get_class($object));
795  $this->‪addCommonFieldsToRow($object, $row);
796  $row['uid'] = $object->‪getUid();
797  if ($dataMap->getLanguageIdColumnName() !== null) {
798  $row[$dataMap->getLanguageIdColumnName()] = (int)$object->‪_getProperty('_languageUid');
799  if ($object->‪_getProperty('_localizedUid') !== null) {
800  $row['uid'] = $object->‪_getProperty('_localizedUid');
801  }
802  }
803  $this->storageBackend->updateRow($dataMap->getTableName(), $row);
804  $this->eventDispatcher->dispatch(new EntityUpdatedInPersistenceEvent($object));
805 
806  $frameworkConfiguration = $this->configurationManager->getConfiguration(‪ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
807  if (($frameworkConfiguration['persistence']['updateReferenceIndex'] ?? '') === '1') {
808  $this->referenceIndex->updateRefIndexTable($dataMap->getTableName(), $row['uid']);
809  }
810  return true;
811  }
812 
819  protected function ‪addCommonFieldsToRow(‪DomainObjectInterface $object, array &$row)
820  {
821  $dataMap = $this->dataMapFactory->buildDataMap(get_class($object));
822  $this->‪addCommonDateFieldsToRow($object, $row);
823  if ($dataMap->getRecordTypeColumnName() !== null && $dataMap->getRecordType() !== null) {
824  $row[$dataMap->getRecordTypeColumnName()] = $dataMap->getRecordType();
825  }
826  if ($object->‪_isNew() && !isset($row['pid'])) {
827  $row['pid'] = $this->‪determineStoragePageIdForNewRecord($object);
828  }
829  }
830 
837  protected function ‪addCommonDateFieldsToRow(DomainObjectInterface $object, array &$row)
838  {
839  $dataMap = $this->dataMapFactory->buildDataMap(get_class($object));
840  if ($object->_isNew() && $dataMap->getCreationDateColumnName() !== null) {
841  $row[$dataMap->getCreationDateColumnName()] = ‪$GLOBALS['EXEC_TIME'];
842  }
843  if ($dataMap->getModificationDateColumnName() !== null) {
844  $row[$dataMap->getModificationDateColumnName()] = ‪$GLOBALS['EXEC_TIME'];
845  }
846  }
847 
851  protected function ‪processDeletedObjects()
852  {
853  foreach ($this->deletedEntities as $entity) {
854  if ($this->session->hasObject($entity)) {
855  $this->‪removeEntity($entity);
856  $this->session->unregisterReconstitutedEntity($entity);
857  $this->session->unregisterObject($entity);
858  }
859  }
860  $this->deletedEntities = new ‪ObjectStorage();
861  }
862 
869  protected function ‪removeEntity(DomainObjectInterface $object, $markAsDeleted = true)
870  {
871  $dataMap = $this->dataMapFactory->buildDataMap(get_class($object));
872  $tableName = $dataMap->getTableName();
873  if ($markAsDeleted === true && $dataMap->getDeletedFlagColumnName() !== null) {
874  $deletedColumnName = $dataMap->getDeletedFlagColumnName();
875  $row = [
876  'uid' => $object->getUid(),
877  $deletedColumnName => 1,
878  ];
879  $this->‪addCommonDateFieldsToRow($object, $row);
880  $this->storageBackend->updateRow($tableName, $row);
881  } else {
882  $this->storageBackend->removeRow($tableName, ['uid' => $object->getUid()]);
883  }
884  $this->eventDispatcher->dispatch(new EntityRemovedFromPersistenceEvent($object));
885 
886  $this->‪removeRelatedObjects($object);
887  $frameworkConfiguration = $this->configurationManager->getConfiguration(‪ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
888  if (($frameworkConfiguration['persistence']['updateReferenceIndex'] ?? '') === '1') {
889  $this->referenceIndex->updateRefIndexTable($tableName, $object->getUid());
890  }
891  }
892 
898  protected function ‪removeRelatedObjects(‪DomainObjectInterface $object)
899  {
900  $className = get_class($object);
901  $dataMap = $this->dataMapFactory->buildDataMap($className);
902  $classSchema = $this->reflectionService->getClassSchema($className);
903  foreach ($classSchema->getDomainObjectProperties() as $property) {
904  $propertyName = $property->getName();
905  $columnMap = $dataMap->getColumnMap($propertyName);
906  if ($columnMap === null) {
907  continue;
908  }
909  $propertyValue = $object->‪_getProperty($propertyName);
910  if ($property->getCascadeValue() === 'remove') {
911  if ($columnMap->getTypeOfRelation() === ‪ColumnMap::RELATION_HAS_MANY) {
912  foreach ($propertyValue as $containedObject) {
913  $this->‪removeEntity($containedObject);
914  }
915  } elseif ($propertyValue instanceof DomainObjectInterface) {
916  $this->‪removeEntity($propertyValue);
917  }
918  } elseif ($dataMap->getDeletedFlagColumnName() === null
919  && $columnMap->getTypeOfRelation() === ‪ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY
920  ) {
921  $this->‪deleteAllRelationsFromRelationtable($object, $propertyName);
922  }
923  }
924  }
925 
937  protected function ‪determineStoragePageIdForNewRecord(‪DomainObjectInterface $object = null)
938  {
939  $frameworkConfiguration = $this->configurationManager->getConfiguration(‪ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
940  if ($object !== null) {
941  if (‪ObjectAccess::isPropertyGettable($object, 'pid')) {
942  $pid = ‪ObjectAccess::getProperty($object, 'pid');
943  if (isset($pid)) {
944  return (int)$pid;
945  }
946  }
947  $className = get_class($object);
948  // todo: decide what to do with this option.
949  if (isset($frameworkConfiguration['persistence']['classes'][$className]) && !empty($frameworkConfiguration['persistence']['classes'][$className]['newRecordStoragePid'])) {
950  return (int)$frameworkConfiguration['persistence']['classes'][$className]['newRecordStoragePid'];
951  }
952  }
953  $storagePidList = ‪GeneralUtility::intExplode(',', $frameworkConfiguration['persistence']['storagePid']);
954  return (int)$storagePidList[0];
955  }
956 
967  protected function ‪getPlainValue($input, ‪ColumnMap $columnMap = null)
968  {
969  return $input !== null
970  ? GeneralUtility::makeInstance(DataMapper::class)->getPlainValue($input, $columnMap)
971  : null;
972  }
973 }
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend
Definition: Backend.php:49
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\$deletedEntities
‪TYPO3 CMS Extbase Persistence ObjectStorage $deletedEntities
Definition: Backend.php:64
‪TYPO3\CMS\Extbase\Event\Persistence\EntityFinalizedAfterPersistenceEvent
Definition: EntityFinalizedAfterPersistenceEvent.php:27
‪TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface\getUid
‪int getUid()
‪TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface
Definition: PersistenceManagerInterface.php:22
‪TYPO3\CMS\Extbase\Annotation
Definition: IgnoreValidation.php:18
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\insertObject
‪insertObject(DomainObjectInterface $object, DomainObjectInterface $parentObject=null, $parentPropertyName='')
Definition: Backend.php:571
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\$reflectionService
‪TYPO3 CMS Extbase Reflection ReflectionService $reflectionService
Definition: Backend.php:76
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\getUidOfAlreadyPersistedValueObject
‪int null getUidOfAlreadyPersistedValueObject(AbstractValueObject $object)
Definition: Backend.php:651
‪TYPO3\CMS\Extbase\Persistence\QueryInterface
Definition: QueryInterface.php:29
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\$storageBackend
‪TYPO3 CMS Extbase Persistence Generic Storage BackendInterface $storageBackend
Definition: Backend.php:80
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\$session
‪TYPO3 CMS Extbase Persistence Generic Session $session
Definition: Backend.php:52
‪TYPO3\CMS\Extbase\Event\Persistence\EntityAddedToPersistenceEvent
Definition: EntityAddedToPersistenceEvent.php:27
‪TYPO3\CMS\Core\Database\ReferenceIndex
Definition: ReferenceIndex.php:42
‪TYPO3
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess\getProperty
‪static mixed getProperty($subject, string $propertyName)
Definition: ObjectAccess.php:61
‪TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface\_setProperty
‪_setProperty(string $propertyName, $value)
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap
Definition: ColumnMap.php:28
‪TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface\_isNew
‪bool _isNew()
‪TYPO3\CMS\Extbase\Persistence\ObjectStorage\getPosition
‪int null getPosition($object)
Definition: ObjectStorage.php:387
‪TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface\_getProperty
‪mixed _getProperty(string $propertyName)
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap\RELATION_HAS_AND_BELONGS_TO_MANY
‪const RELATION_HAS_AND_BELONGS_TO_MANY
Definition: ColumnMap.php:52
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\addCommonFieldsToRow
‪addCommonFieldsToRow(DomainObjectInterface $object, array &$row)
Definition: Backend.php:806
‪TYPO3\CMS\Extbase\Event\Persistence\EntityRemovedFromPersistenceEvent
Definition: EntityRemovedFromPersistenceEvent.php:26
‪TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
Definition: ConfigurationManagerInterface.php:28
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\attachObjectToParentObject
‪attachObjectToParentObject(DomainObjectInterface $object, DomainObjectInterface $parentObject, $parentPropertyName, $sortingPosition=0)
Definition: Backend.php:454
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\persistObjectStorage
‪persistObjectStorage(ObjectStorage $objectStorage, DomainObjectInterface $parentObject, $propertyName, array &$row)
Definition: Backend.php:368
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\processDeletedObjects
‪processDeletedObjects()
Definition: Backend.php:838
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper
Definition: DataMapper.php:51
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\persistObject
‪persistObject(DomainObjectInterface $object)
Definition: Backend.php:280
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\commit
‪commit()
Definition: Backend.php:251
‪TYPO3\CMS\Extbase\Event\Persistence\ModifyResultAfterFetchingObjectDataEvent
Definition: ModifyResultAfterFetchingObjectDataEvent.php:26
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\$configurationManager
‪TYPO3 CMS Extbase Configuration ConfigurationManagerInterface $configurationManager
Definition: Backend.php:94
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap\RELATION_HAS_MANY
‪const RELATION_HAS_MANY
Definition: ColumnMap.php:42
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess
Definition: ObjectAccess.php:39
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap\RELATION_HAS_ONE
‪const RELATION_HAS_ONE
Definition: ColumnMap.php:37
‪TYPO3\CMS\Extbase\Persistence\ObjectStorage
Definition: ObjectStorage.php:32
‪TYPO3\CMS\Extbase\Persistence\Exception\IllegalRelationTypeException
Definition: IllegalRelationTypeException.php:25
‪TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface\CONFIGURATION_TYPE_FRAMEWORK
‪const CONFIGURATION_TYPE_FRAMEWORK
Definition: ConfigurationManagerInterface.php:29
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory
Definition: DataMapFactory.php:39
‪TYPO3\CMS\Extbase\Reflection\ReflectionService
Definition: ReflectionService.php:28
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\setPersistenceManager
‪setPersistenceManager(PersistenceManagerInterface $persistenceManager)
Definition: Backend.php:138
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\removeRelatedObjects
‪removeRelatedObjects(DomainObjectInterface $object)
Definition: Backend.php:885
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\$eventDispatcher
‪EventDispatcherInterface $eventDispatcher
Definition: Backend.php:102
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\getPlainValue
‪int string null getPlainValue($input, ColumnMap $columnMap=null)
Definition: Backend.php:954
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess\isPropertyGettable
‪static bool isPropertyGettable($object, $propertyName)
Definition: ObjectAccess.php:352
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\$aggregateRootObjects
‪TYPO3 CMS Extbase Persistence ObjectStorage $aggregateRootObjects
Definition: Backend.php:60
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\propertyValueIsLazyLoaded
‪bool propertyValueIsLazyLoaded($propertyValue)
Definition: Backend.php:344
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\determineStoragePageIdForNewRecord
‪int determineStoragePageIdForNewRecord(DomainObjectInterface $object=null)
Definition: Backend.php:924
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\getObjectCountByQuery
‪int getObjectCountByQuery(QueryInterface $query)
Definition: Backend.php:149
‪TYPO3\CMS\Extbase\Persistence\Generic\BackendInterface
Definition: BackendInterface.php:26
‪TYPO3\CMS\Extbase\DomainObject\AbstractValueObject
Definition: AbstractValueObject.php:24
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\$visitedDuringPersistence
‪TYPO3 CMS Extbase Persistence ObjectStorage $visitedDuringPersistence
Definition: Backend.php:72
‪TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface
Definition: DomainObjectInterface.php:29
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\getObjectDataByQuery
‪array getObjectDataByQuery(QueryInterface $query)
Definition: Backend.php:160
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\$referenceIndex
‪TYPO3 CMS Core Database ReferenceIndex $referenceIndex
Definition: Backend.php:90
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\setAggregateRootObjects
‪setAggregateRootObjects(ObjectStorage $objects)
Definition: Backend.php:223
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\removeEntity
‪removeEntity(DomainObjectInterface $object, $markAsDeleted=true)
Definition: Backend.php:856
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap\RELATION_NONE
‪const RELATION_NONE
Definition: ColumnMap.php:32
‪TYPO3\CMS\Extbase\Persistence\Generic\Session
Definition: Session.php:27
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\setChangedEntities
‪setChangedEntities(ObjectStorage $entities)
Definition: Backend.php:233
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\__construct
‪__construct(ConfigurationManagerInterface $configurationManager, Session $session, ReflectionService $reflectionService, \TYPO3\CMS\Extbase\Persistence\Generic\Storage\BackendInterface $storageBackend, DataMapFactory $dataMapFactory, EventDispatcherInterface $eventDispatcher)
Definition: Backend.php:114
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\deleteAllRelationsFromRelationtable
‪bool deleteAllRelationsFromRelationtable(DomainObjectInterface $parentObject, $parentPropertyName)
Definition: Backend.php:731
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\insertRelationInRelationtable
‪int insertRelationInRelationtable(DomainObjectInterface $object, DomainObjectInterface $parentObject, $propertyName, $sortingPosition=null)
Definition: Backend.php:665
‪TYPO3\CMS\Extbase\Event\Persistence\EntityUpdatedInPersistenceEvent
Definition: EntityUpdatedInPersistenceEvent.php:26
‪TYPO3\CMS\Extbase\Persistence\Generic
Definition: Backend.php:16
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\updateRelationInRelationTable
‪bool updateRelationInRelationTable(DomainObjectInterface $object, DomainObjectInterface $parentObject, $propertyName, $sortingPosition=0)
Definition: Backend.php:703
‪TYPO3\CMS\Extbase\Event\Persistence\ModifyQueryBeforeFetchingObjectDataEvent
Definition: ModifyQueryBeforeFetchingObjectDataEvent.php:26
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\$dataMapFactory
‪TYPO3 CMS Extbase Persistence Generic Mapper DataMapFactory $dataMapFactory
Definition: Backend.php:84
‪TYPO3\CMS\Extbase\Persistence\ObjectStorage\isRelationDirty
‪bool isRelationDirty($object)
Definition: ObjectStorage.php:376
‪TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy
Definition: LazyLoadingProxy.php:29
‪TYPO3\CMS\Core\SingletonInterface
Definition: SingletonInterface.php:22
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\getRemovedChildObjects
‪array getRemovedChildObjects(DomainObjectInterface $object, $propertyName)
Definition: Backend.php:431
‪TYPO3\CMS\Core\Utility\GeneralUtility\intExplode
‪static int[] intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:927
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\isNewObject
‪bool isNewObject($object)
Definition: Backend.php:213
‪TYPO3\CMS\Extbase\Event\Persistence\EntityPersistedEvent
Definition: EntityPersistedEvent.php:26
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\getObjectByIdentifier
‪object null getObjectByIdentifier($identifier, $className)
Definition: Backend.php:195
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\updateRelationOfObjectToParentObject
‪updateRelationOfObjectToParentObject(DomainObjectInterface $object, DomainObjectInterface $parentObject, $parentPropertyName, $sortingPosition=0)
Definition: Backend.php:474
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\persistObjects
‪persistObjects()
Definition: Backend.php:260
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\$changedEntities
‪TYPO3 CMS Extbase Persistence ObjectStorage $changedEntities
Definition: Backend.php:68
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Extbase\Persistence\Generic\LazyObjectStorage
Definition: LazyObjectStorage.php:32
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\attachObjectToParentObjectRelationHasMany
‪attachObjectToParentObjectRelationHasMany(DomainObjectInterface $object, DomainObjectInterface $parentObject, $parentPropertyName, $sortingPosition=0)
Definition: Backend.php:494
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\setDeletedEntities
‪setDeletedEntities(ObjectStorage $entities)
Definition: Backend.php:243
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\updateObject
‪bool updateObject(DomainObjectInterface $object, array $row)
Definition: Backend.php:779
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\detachObjectFromParentObject
‪detachObjectFromParentObject(DomainObjectInterface $object, DomainObjectInterface $parentObject, $parentPropertyName)
Definition: Backend.php:534
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\addCommonDateFieldsToRow
‪addCommonDateFieldsToRow(DomainObjectInterface $object, array &$row)
Definition: Backend.php:824
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\$signalSlotDispatcher
‪TYPO3 CMS Extbase SignalSlot Dispatcher $signalSlotDispatcher
Definition: Backend.php:98
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\deleteRelationFromRelationtable
‪bool deleteRelationFromRelationtable(DomainObjectInterface $relatedObject, DomainObjectInterface $parentObject, $parentPropertyName)
Definition: Backend.php:755
‪TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface\setPid
‪setPid(int $pid)
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\$persistenceManager
‪TYPO3 CMS Extbase Persistence PersistenceManagerInterface $persistenceManager
Definition: Backend.php:56
‪TYPO3\CMS\Extbase\Persistence\ObjectMonitoringInterface
Definition: ObjectMonitoringInterface.php:25
‪TYPO3\CMS\Extbase\Persistence\Generic\Backend\getIdentifierByObject
‪string null getIdentifierByObject($object)
Definition: Backend.php:178
‪TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface\_getCleanProperty
‪mixed _getCleanProperty(string $propertyName)