TYPO3 CMS  TYPO3_8-7
Backend.php
Go to the documentation of this file.
1 <?php
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
20 
26 {
30  protected $session;
31 
36 
41 
45  protected $deletedEntities;
46 
50  protected $changedEntities;
51 
56 
60  protected $reflectionService;
61 
65  protected $qomFactory;
66 
70  protected $storageBackend;
71 
75  protected $dataMapper;
76 
82  protected $referenceIndex;
83 
88 
93 
97  public function injectSession(\TYPO3\CMS\Extbase\Persistence\Generic\Session $session)
98  {
99  $this->session = $session;
100  }
101 
105  public function injectReflectionService(\TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService)
106  {
107  $this->reflectionService = $reflectionService;
108  }
109 
113  public function injectQomFactory(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory)
114  {
115  $this->qomFactory = $qomFactory;
116  }
117 
121  public function injectStorageBackend(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\BackendInterface $storageBackend)
122  {
123  $this->storageBackend = $storageBackend;
124  }
125 
129  public function injectDataMapper(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper $dataMapper)
130  {
131  $this->dataMapper = $dataMapper;
132  }
133 
137  public function injectSignalSlotDispatcher(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher)
138  {
139  $this->signalSlotDispatcher = $signalSlotDispatcher;
140  }
141 
147  public function __construct(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager)
148  {
149  $this->configurationManager = $configurationManager;
150  $this->referenceIndex = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ReferenceIndex::class);
151  $this->aggregateRootObjects = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
152  $this->deletedEntities = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
153  $this->changedEntities = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
154  }
155 
160  {
161  $this->persistenceManager = $persistenceManager;
162  }
163 
169  public function getSession()
170  {
171  return $this->session;
172  }
173 
179  public function getDataMapper()
180  {
181  return $this->dataMapper;
182  }
183 
189  public function getQomFactory()
190  {
191  return $this->qomFactory;
192  }
193 
199  public function getReflectionService()
200  {
202  }
203 
211  public function getObjectCountByQuery(\TYPO3\CMS\Extbase\Persistence\QueryInterface $query)
212  {
213  return $this->storageBackend->getObjectCountByQuery($query);
214  }
215 
223  public function getObjectDataByQuery(\TYPO3\CMS\Extbase\Persistence\QueryInterface $query)
224  {
225  $query = $this->emitBeforeGettingObjectDataSignal($query);
226  $result = $this->storageBackend->getObjectDataByQuery($query);
227  $result = $this->emitAfterGettingObjectDataSignal($query, $result);
228  return $result;
229  }
230 
237  protected function emitBeforeGettingObjectDataSignal(\TYPO3\CMS\Extbase\Persistence\QueryInterface $query)
238  {
239  $signalArguments = $this->signalSlotDispatcher->dispatch(__CLASS__, 'beforeGettingObjectData', [$query]);
240  return $signalArguments[0];
241  }
242 
250  protected function emitAfterGettingObjectDataSignal(\TYPO3\CMS\Extbase\Persistence\QueryInterface $query, array $result)
251  {
252  $signalArguments = $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterGettingObjectData', [$query, $result]);
253  return $signalArguments[1];
254  }
255 
263  public function getIdentifierByObject($object)
264  {
265  if ($object instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy) {
266  $object = $object->_loadRealInstance();
267  if (!is_object($object)) {
268  return null;
269  }
270  }
271  return $this->session->getIdentifierByObject($object);
272  }
273 
282  public function getObjectByIdentifier($identifier, $className)
283  {
284  if ($this->session->hasIdentifier($identifier, $className)) {
285  return $this->session->getObjectByIdentifier($identifier, $className);
286  }
287  $query = $this->persistenceManager->createQueryForType($className);
288  $query->getQuerySettings()->setRespectStoragePage(false);
289  $query->getQuerySettings()->setRespectSysLanguage(false);
290  return $query->matching($query->equals('uid', $identifier))->execute()->getFirst();
291  }
292 
299  public function isNewObject($object)
300  {
301  return $this->getIdentifierByObject($object) === null;
302  }
303 
309  public function setAggregateRootObjects(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $objects)
310  {
311  $this->aggregateRootObjects = $objects;
312  }
313 
319  public function setChangedEntities(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $entities)
320  {
321  $this->changedEntities = $entities;
322  }
323 
329  public function setDeletedEntities(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $entities)
330  {
331  $this->deletedEntities = $entities;
332  }
333 
337  public function commit()
338  {
339  $this->persistObjects();
340  $this->processDeletedObjects();
341  }
342 
346  protected function persistObjects()
347  {
348  $this->visitedDuringPersistence = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
349  foreach ($this->aggregateRootObjects as $object) {
351  if ($object->_isNew()) {
352  $this->insertObject($object);
353  }
354  $this->persistObject($object, null);
355  }
356  foreach ($this->changedEntities as $object) {
357  $this->persistObject($object, null);
358  }
359  }
360 
366  protected function persistObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object)
367  {
368  if (isset($this->visitedDuringPersistence[$object])) {
369  return;
370  }
371  $row = [];
372  $queue = [];
373  $dataMap = $this->dataMapper->getDataMap(get_class($object));
374  $properties = $object->_getProperties();
375  foreach ($properties as $propertyName => $propertyValue) {
376  if (!$dataMap->isPersistableProperty($propertyName) || $this->propertyValueIsLazyLoaded($propertyValue)) {
377  continue;
378  }
379  $columnMap = $dataMap->getColumnMap($propertyName);
380  if ($propertyValue instanceof \TYPO3\CMS\Extbase\Persistence\ObjectStorage) {
381  $cleanProperty = $object->_getCleanProperty($propertyName);
382  // objectstorage needs to be persisted if the object is new, the objectstorge is dirty, meaning it has
383  // been changed after initial build, or an empty objectstorge is present and the cleanstate objectstorage
384  // has childelements, meaning all elements should been removed from the objectstorage
385  if ($object->_isNew() || $propertyValue->_isDirty() || ($propertyValue->count() === 0 && $cleanProperty && $cleanProperty->count() > 0)) {
386  $this->persistObjectStorage($propertyValue, $object, $propertyName, $row);
387  $propertyValue->_memorizeCleanState();
388  }
389  foreach ($propertyValue as $containedObject) {
390  if ($containedObject instanceof \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface) {
391  $queue[] = $containedObject;
392  }
393  }
394  } elseif ($propertyValue instanceof \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface
395  && $object instanceof ObjectMonitoringInterface) {
396  if ($object->_isDirty($propertyName)) {
397  if ($propertyValue->_isNew()) {
398  $this->insertObject($propertyValue, $object, $propertyName);
399  }
400  $row[$columnMap->getColumnName()] = $this->getPlainValue($propertyValue);
401  }
402  $queue[] = $propertyValue;
403  } elseif ($object->_isNew() || $object->_isDirty($propertyName)) {
404  $row[$columnMap->getColumnName()] = $this->getPlainValue($propertyValue, $columnMap);
405  }
406  }
407  if (!empty($row)) {
408  $this->updateObject($object, $row);
409  $object->_memorizeCleanState();
410  }
411  $this->visitedDuringPersistence[$object] = $object->getUid();
412  foreach ($queue as $queuedObject) {
413  $this->persistObject($queuedObject);
414  }
415  $this->emitAfterPersistObjectSignal($object);
416  }
417 
424  protected function propertyValueIsLazyLoaded($propertyValue)
425  {
426  if ($propertyValue instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy) {
427  return true;
428  }
429  if ($propertyValue instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyObjectStorage) {
430  if ($propertyValue->isInitialized() === false) {
431  return true;
432  }
433  }
434  return false;
435  }
436 
447  protected function persistObjectStorage(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $objectStorage, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $propertyName, array &$row)
448  {
449  $className = get_class($parentObject);
450  $columnMap = $this->dataMapper->getDataMap($className)->getColumnMap($propertyName);
451  $propertyMetaData = $this->reflectionService->getClassSchema($className)->getProperty($propertyName);
452  foreach ($this->getRemovedChildObjects($parentObject, $propertyName) as $removedObject) {
453  $this->detachObjectFromParentObject($removedObject, $parentObject, $propertyName);
454  if ($columnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_MANY && $propertyMetaData['cascade'] === 'remove') {
455  $this->removeEntity($removedObject);
456  }
457  }
458 
459  $currentUids = [];
460  $sortingPosition = 1;
461  $updateSortingOfFollowing = false;
462 
463  foreach ($objectStorage as $object) {
465  if (empty($currentUids)) {
466  $sortingPosition = 1;
467  } else {
468  $sortingPosition++;
469  }
470  $cleanProperty = $parentObject->_getCleanProperty($propertyName);
471  if ($object->_isNew()) {
472  $this->insertObject($object);
473  $this->attachObjectToParentObject($object, $parentObject, $propertyName, $sortingPosition);
474  // if a new object is inserted, all objects after this need to have their sorting updated
475  $updateSortingOfFollowing = true;
476  } elseif ($cleanProperty === null || $cleanProperty->getPosition($object) === null) {
477  // if parent object is new then it doesn't have cleanProperty yet; before attaching object it's clean position is null
478  $this->attachObjectToParentObject($object, $parentObject, $propertyName, $sortingPosition);
479  // 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
480  $updateSortingOfFollowing = true;
481  } elseif ($objectStorage->isRelationDirty($object) || $cleanProperty->getPosition($object) !== $objectStorage->getPosition($object)) {
482  $this->updateRelationOfObjectToParentObject($object, $parentObject, $propertyName, $sortingPosition);
483  $updateSortingOfFollowing = true;
484  } elseif ($updateSortingOfFollowing) {
485  if ($sortingPosition > $objectStorage->getPosition($object)) {
486  $this->updateRelationOfObjectToParentObject($object, $parentObject, $propertyName, $sortingPosition);
487  } else {
488  $sortingPosition = $objectStorage->getPosition($object);
489  }
490  }
491  $currentUids[] = $object->getUid();
492  }
493 
494  if ($columnMap->getParentKeyFieldName() === null) {
495  $row[$columnMap->getColumnName()] = implode(',', $currentUids);
496  } else {
497  $row[$columnMap->getColumnName()] = $this->dataMapper->countRelated($parentObject, $propertyName);
498  }
499  }
500 
509  protected function getRemovedChildObjects(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, $propertyName)
510  {
511  $removedObjects = [];
512  $cleanPropertyValue = $object->_getCleanProperty($propertyName);
513  if (is_array($cleanPropertyValue) || $cleanPropertyValue instanceof \Iterator) {
514  $propertyValue = $object->_getProperty($propertyName);
515  foreach ($cleanPropertyValue as $containedObject) {
516  if (!$propertyValue->contains($containedObject)) {
517  $removedObjects[] = $containedObject;
518  }
519  }
520  }
521  return $removedObjects;
522  }
523 
532  protected function attachObjectToParentObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $parentPropertyName, $sortingPosition = 0)
533  {
534  $parentDataMap = $this->dataMapper->getDataMap(get_class($parentObject));
535  $parentColumnMap = $parentDataMap->getColumnMap($parentPropertyName);
536  if ($parentColumnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_MANY) {
537  $this->attachObjectToParentObjectRelationHasMany($object, $parentObject, $parentPropertyName, $sortingPosition);
538  } elseif ($parentColumnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
539  $this->insertRelationInRelationtable($object, $parentObject, $parentPropertyName, $sortingPosition);
540  }
541  }
542 
551  protected function updateRelationOfObjectToParentObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\AbstractEntity $parentObject, $parentPropertyName, $sortingPosition = 0)
552  {
553  $parentDataMap = $this->dataMapper->getDataMap(get_class($parentObject));
554  $parentColumnMap = $parentDataMap->getColumnMap($parentPropertyName);
555  if ($parentColumnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_MANY) {
556  $this->attachObjectToParentObjectRelationHasMany($object, $parentObject, $parentPropertyName, $sortingPosition);
557  } elseif ($parentColumnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
558  $this->updateRelationInRelationTable($object, $parentObject, $parentPropertyName, $sortingPosition);
559  }
560  }
561 
571  protected function attachObjectToParentObjectRelationHasMany(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\AbstractEntity $parentObject, $parentPropertyName, $sortingPosition = 0)
572  {
573  $parentDataMap = $this->dataMapper->getDataMap(get_class($parentObject));
574  $parentColumnMap = $parentDataMap->getColumnMap($parentPropertyName);
575  if ($parentColumnMap->getTypeOfRelation() !== \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_MANY) {
576  throw new \TYPO3\CMS\Extbase\Persistence\Exception\IllegalRelationTypeException(
577  'Parent column relation type is ' . $parentColumnMap->getTypeOfRelation() .
579  1345368105
580  );
581  }
582  $row = [];
583  $parentKeyFieldName = $parentColumnMap->getParentKeyFieldName();
584  if ($parentKeyFieldName !== null) {
585  $row[$parentKeyFieldName] = $parentObject->getUid();
586  $parentTableFieldName = $parentColumnMap->getParentTableFieldName();
587  if ($parentTableFieldName !== null) {
588  $row[$parentTableFieldName] = $parentDataMap->getTableName();
589  }
590  $relationTableMatchFields = $parentColumnMap->getRelationTableMatchFields();
591  if (is_array($relationTableMatchFields)) {
592  $row = array_merge($relationTableMatchFields, $row);
593  }
594  }
595  $childSortByFieldName = $parentColumnMap->getChildSortByFieldName();
596  if (!empty($childSortByFieldName)) {
597  $row[$childSortByFieldName] = $sortingPosition;
598  }
599  if (!empty($row)) {
600  $this->updateObject($object, $row);
601  }
602  }
603 
611  protected function detachObjectFromParentObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $parentPropertyName)
612  {
613  $parentDataMap = $this->dataMapper->getDataMap(get_class($parentObject));
614  $parentColumnMap = $parentDataMap->getColumnMap($parentPropertyName);
615  if ($parentColumnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_MANY) {
616  $row = [];
617  $parentKeyFieldName = $parentColumnMap->getParentKeyFieldName();
618  if ($parentKeyFieldName !== null) {
619  $row[$parentKeyFieldName] = 0;
620  $parentTableFieldName = $parentColumnMap->getParentTableFieldName();
621  if ($parentTableFieldName !== null) {
622  $row[$parentTableFieldName] = '';
623  }
624  $relationTableMatchFields = $parentColumnMap->getRelationTableMatchFields();
625  if (is_array($relationTableMatchFields) && !empty($relationTableMatchFields)) {
626  $row = array_merge(array_fill_keys(array_keys($relationTableMatchFields), ''), $row);
627  }
628  }
629  $childSortByFieldName = $parentColumnMap->getChildSortByFieldName();
630  if (!empty($childSortByFieldName)) {
631  $row[$childSortByFieldName] = 0;
632  }
633  if (!empty($row)) {
634  $this->updateObject($object, $row);
635  }
636  } elseif ($parentColumnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
637  $this->deleteRelationFromRelationtable($object, $parentObject, $parentPropertyName);
638  }
639  }
640 
648  protected function insertObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject = null, $parentPropertyName = '')
649  {
650  if ($object instanceof \TYPO3\CMS\Extbase\DomainObject\AbstractValueObject) {
651  $result = $this->getUidOfAlreadyPersistedValueObject($object);
652  if ($result !== false) {
653  $object->_setProperty('uid', (int)$result);
654  return;
655  }
656  }
657  $dataMap = $this->dataMapper->getDataMap(get_class($object));
658  $row = [];
659  $properties = $object->_getProperties();
660  foreach ($properties as $propertyName => $propertyValue) {
661  if (!$dataMap->isPersistableProperty($propertyName) || $this->propertyValueIsLazyLoaded($propertyValue)) {
662  continue;
663  }
664  $columnMap = $dataMap->getColumnMap($propertyName);
665  if ($columnMap->getTypeOfRelation() === ColumnMap::RELATION_HAS_ONE) {
666  $row[$columnMap->getColumnName()] = 0;
667  } elseif ($columnMap->getTypeOfRelation() !== ColumnMap::RELATION_NONE) {
668  if ($columnMap->getParentKeyFieldName() === null) {
669  // CSV type relation
670  $row[$columnMap->getColumnName()] = '';
671  } else {
672  // MM type relation
673  $row[$columnMap->getColumnName()] = 0;
674  }
675  } elseif ($propertyValue !== null) {
676  $row[$columnMap->getColumnName()] = $this->getPlainValue($propertyValue, $columnMap);
677  }
678  }
679  $this->addCommonFieldsToRow($object, $row);
680  if ($dataMap->getLanguageIdColumnName() !== null && $object->_getProperty('_languageUid') === null) {
681  $row[$dataMap->getLanguageIdColumnName()] = 0;
682  $object->_setProperty('_languageUid', 0);
683  }
684  if ($dataMap->getTranslationOriginColumnName() !== null) {
685  $row[$dataMap->getTranslationOriginColumnName()] = 0;
686  }
687  if ($dataMap->getTranslationOriginDiffSourceName() !== null) {
688  $row[$dataMap->getTranslationOriginDiffSourceName()] = '';
689  }
690  if ($parentObject !== null && $parentPropertyName) {
691  $parentColumnDataMap = $this->dataMapper->getDataMap(get_class($parentObject))->getColumnMap($parentPropertyName);
692  $relationTableMatchFields = $parentColumnDataMap->getRelationTableMatchFields();
693  if (is_array($relationTableMatchFields)) {
694  $row = array_merge($relationTableMatchFields, $row);
695  }
696  if ($parentColumnDataMap->getParentKeyFieldName() !== null) {
697  $row[$parentColumnDataMap->getParentKeyFieldName()] = (int)$parentObject->getUid();
698  }
699  }
700  $uid = $this->storageBackend->addRow($dataMap->getTableName(), $row);
701  $object->_setProperty('uid', (int)$uid);
702  $object->setPid((int)$row['pid']);
703  if ((int)$uid >= 1) {
704  $this->emitAfterInsertObjectSignal($object);
705  }
706  $frameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
707  if ($frameworkConfiguration['persistence']['updateReferenceIndex'] === '1') {
708  $this->referenceIndex->updateRefIndexTable($dataMap->getTableName(), $uid);
709  }
710  $this->session->registerObject($object, $uid);
711  if ((int)$uid >= 1) {
712  $this->emitEndInsertObjectSignal($object);
713  }
714  }
715 
722  {
723  $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterInsertObject', [$object]);
724  }
725 
733  {
734  $this->signalSlotDispatcher->dispatch(__CLASS__, 'endInsertObject', [$object]);
735  }
736 
743  protected function getUidOfAlreadyPersistedValueObject(\TYPO3\CMS\Extbase\DomainObject\AbstractValueObject $object)
744  {
745  return $this->storageBackend->getUidOfAlreadyPersistedValueObject($object);
746  }
747 
757  protected function insertRelationInRelationtable(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $propertyName, $sortingPosition = null)
758  {
759  $dataMap = $this->dataMapper->getDataMap(get_class($parentObject));
760  $columnMap = $dataMap->getColumnMap($propertyName);
761  $parentUid = $parentObject->getUid();
762  if ($parentObject->_getProperty('_localizedUid') !== null) {
763  $parentUid = $parentObject->_getProperty('_localizedUid');
764  }
765  $row = [
766  $columnMap->getParentKeyFieldName() => (int)$parentUid,
767  $columnMap->getChildKeyFieldName() => (int)$object->getUid(),
768  $columnMap->getChildSortByFieldName() => !is_null($sortingPosition) ? (int)$sortingPosition : 0
769  ];
770  $relationTableName = $columnMap->getRelationTableName();
771  if ($columnMap->getRelationTablePageIdColumnName() !== null) {
772  $row[$columnMap->getRelationTablePageIdColumnName()] = $this->determineStoragePageIdForNewRecord();
773  }
774  $relationTableMatchFields = $columnMap->getRelationTableMatchFields();
775  if (is_array($relationTableMatchFields)) {
776  $row = array_merge($relationTableMatchFields, $row);
777  }
778  $relationTableInsertFields = $columnMap->getRelationTableInsertFields();
779  if (is_array($relationTableInsertFields)) {
780  $row = array_merge($relationTableInsertFields, $row);
781  }
782  $res = $this->storageBackend->addRow($relationTableName, $row, true);
783  return $res;
784  }
785 
795  protected function updateRelationInRelationTable(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $propertyName, $sortingPosition = 0)
796  {
797  $dataMap = $this->dataMapper->getDataMap(get_class($parentObject));
798  $columnMap = $dataMap->getColumnMap($propertyName);
799  $row = [
800  $columnMap->getParentKeyFieldName() => (int)$parentObject->getUid(),
801  $columnMap->getChildKeyFieldName() => (int)$object->getUid(),
802  $columnMap->getChildSortByFieldName() => (int)$sortingPosition
803  ];
804  $relationTableName = $columnMap->getRelationTableName();
805  $relationTableMatchFields = $columnMap->getRelationTableMatchFields();
806  if (is_array($relationTableMatchFields)) {
807  $row = array_merge($relationTableMatchFields, $row);
808  }
809  $res = $this->storageBackend->updateRelationTableRow(
810  $relationTableName,
811  $row
812  );
813  return $res;
814  }
815 
823  protected function deleteAllRelationsFromRelationtable(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $parentPropertyName)
824  {
825  $dataMap = $this->dataMapper->getDataMap(get_class($parentObject));
826  $columnMap = $dataMap->getColumnMap($parentPropertyName);
827  $relationTableName = $columnMap->getRelationTableName();
828  $relationMatchFields = [
829  $columnMap->getParentKeyFieldName() => (int)$parentObject->getUid()
830  ];
831  $relationTableMatchFields = $columnMap->getRelationTableMatchFields();
832  if (is_array($relationTableMatchFields)) {
833  $relationMatchFields = array_merge($relationTableMatchFields, $relationMatchFields);
834  }
835  $res = $this->storageBackend->removeRow($relationTableName, $relationMatchFields, false);
836  return $res;
837  }
838 
847  protected function deleteRelationFromRelationtable(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $relatedObject, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $parentPropertyName)
848  {
849  $dataMap = $this->dataMapper->getDataMap(get_class($parentObject));
850  $columnMap = $dataMap->getColumnMap($parentPropertyName);
851  $relationTableName = $columnMap->getRelationTableName();
852  $relationMatchFields = [
853  $columnMap->getParentKeyFieldName() => (int)$parentObject->getUid(),
854  $columnMap->getChildKeyFieldName() => (int)$relatedObject->getUid()
855  ];
856  $relationTableMatchFields = $columnMap->getRelationTableMatchFields();
857  if (is_array($relationTableMatchFields)) {
858  $relationMatchFields = array_merge($relationTableMatchFields, $relationMatchFields);
859  }
860  $res = $this->storageBackend->removeRow($relationTableName, $relationMatchFields, false);
861  return $res;
862  }
863 
872  protected function fetchMaxSortingFromParentTable(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $parentPropertyName)
873  {
874  $parentDataMap = $this->dataMapper->getDataMap(get_class($parentObject));
875  $parentColumnMap = $parentDataMap->getColumnMap($parentPropertyName);
876  if ($parentColumnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_MANY) {
877  $tableName = $parentColumnMap->getChildTableName();
878  $sortByFieldName = $parentColumnMap->getChildSortByFieldName();
879 
880  if (empty($sortByFieldName)) {
881  return false;
882  }
883  $matchFields = [];
884  $parentKeyFieldName = $parentColumnMap->getParentKeyFieldName();
885  if ($parentKeyFieldName !== null) {
886  $matchFields[$parentKeyFieldName] = $parentObject->getUid();
887  $parentTableFieldName = $parentColumnMap->getParentTableFieldName();
888  if ($parentTableFieldName !== null) {
889  $matchFields[$parentTableFieldName] = $parentDataMap->getTableName();
890  }
891  }
892 
893  if (empty($matchFields)) {
894  return false;
895  }
896  } elseif ($parentColumnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
897  $tableName = $parentColumnMap->getRelationTableName();
898  $sortByFieldName = $parentColumnMap->getChildSortByFieldName();
899 
900  $matchFields = [
901  $parentColumnMap->getParentKeyFieldName() => (int)$parentObject->getUid()
902  ];
903 
904  $relationTableMatchFields = $parentColumnMap->getRelationTableMatchFields();
905  if (is_array($relationTableMatchFields)) {
906  $matchFields = array_merge($relationTableMatchFields, $matchFields);
907  }
908  } else {
909  throw new \TYPO3\CMS\Extbase\Persistence\Exception\IllegalRelationTypeException('Unexpected parent column relation type: ' . $parentColumnMap->getTypeOfRelation(), 1345368106);
910  }
911 
912  $result = $this->storageBackend->getMaxValueFromTable(
913  $tableName,
914  $matchFields,
915  $sortByFieldName
916  );
917  return $result;
918  }
919 
927  protected function updateObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, array $row)
928  {
929  $dataMap = $this->dataMapper->getDataMap(get_class($object));
930  $this->addCommonFieldsToRow($object, $row);
931  $row['uid'] = $object->getUid();
932  if ($dataMap->getLanguageIdColumnName() !== null) {
933  $row[$dataMap->getLanguageIdColumnName()] = (int)$object->_getProperty('_languageUid');
934  if ($object->_getProperty('_localizedUid') !== null) {
935  $row['uid'] = $object->_getProperty('_localizedUid');
936  }
937  }
938  $res = $this->storageBackend->updateRow($dataMap->getTableName(), $row);
939  if ($res === true) {
940  $this->emitAfterUpdateObjectSignal($object);
941  }
942  $frameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
943  if ($frameworkConfiguration['persistence']['updateReferenceIndex'] === '1') {
944  $this->referenceIndex->updateRefIndexTable($dataMap->getTableName(), $row['uid']);
945  }
946  return $res;
947  }
948 
955  {
956  $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterUpdateObject', [$object]);
957  }
958 
965  {
966  $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterPersistObject', [$object]);
967  }
968 
975  protected function addCommonFieldsToRow(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, array &$row)
976  {
977  $dataMap = $this->dataMapper->getDataMap(get_class($object));
978  $this->addCommonDateFieldsToRow($object, $row);
979  if ($dataMap->getRecordTypeColumnName() !== null && $dataMap->getRecordType() !== null) {
980  $row[$dataMap->getRecordTypeColumnName()] = $dataMap->getRecordType();
981  }
982  if ($object->_isNew() && !isset($row['pid'])) {
983  $row['pid'] = $this->determineStoragePageIdForNewRecord($object);
984  }
985  }
986 
993  protected function addCommonDateFieldsToRow(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, array &$row)
994  {
995  $dataMap = $this->dataMapper->getDataMap(get_class($object));
996  if ($object->_isNew() && $dataMap->getCreationDateColumnName() !== null) {
997  $row[$dataMap->getCreationDateColumnName()] = $GLOBALS['EXEC_TIME'];
998  }
999  if ($dataMap->getModificationDateColumnName() !== null) {
1000  $row[$dataMap->getModificationDateColumnName()] = $GLOBALS['EXEC_TIME'];
1001  }
1002  }
1003 
1007  protected function processDeletedObjects()
1008  {
1009  foreach ($this->deletedEntities as $entity) {
1010  if ($this->session->hasObject($entity)) {
1011  $this->removeEntity($entity);
1012  $this->session->unregisterReconstitutedEntity($entity);
1013  $this->session->unregisterObject($entity);
1014  }
1015  }
1016  $this->deletedEntities = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
1017  }
1018 
1025  protected function removeEntity(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, $markAsDeleted = true)
1026  {
1027  $dataMap = $this->dataMapper->getDataMap(get_class($object));
1028  $tableName = $dataMap->getTableName();
1029  if ($markAsDeleted === true && $dataMap->getDeletedFlagColumnName() !== null) {
1030  $deletedColumnName = $dataMap->getDeletedFlagColumnName();
1031  $row = [
1032  'uid' => $object->getUid(),
1033  $deletedColumnName => 1
1034  ];
1035  $this->addCommonDateFieldsToRow($object, $row);
1036  $res = $this->storageBackend->updateRow($tableName, $row);
1037  } else {
1038  $res = $this->storageBackend->removeRow($tableName, ['uid' => $object->getUid()]);
1039  }
1040  if ($res === true) {
1041  $this->emitAfterRemoveObjectSignal($object);
1042  }
1043  $this->removeRelatedObjects($object);
1044  $frameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
1045  if ($frameworkConfiguration['persistence']['updateReferenceIndex'] === '1') {
1046  $this->referenceIndex->updateRefIndexTable($tableName, $object->getUid());
1047  }
1048  }
1049 
1056  {
1057  $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterRemoveObject', [$object]);
1058  }
1059 
1065  protected function removeRelatedObjects(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object)
1066  {
1067  $className = get_class($object);
1068  $dataMap = $this->dataMapper->getDataMap($className);
1069  $classSchema = $this->reflectionService->getClassSchema($className);
1070  $properties = $object->_getProperties();
1071  foreach ($properties as $propertyName => $propertyValue) {
1072  $columnMap = $dataMap->getColumnMap($propertyName);
1073  if ($columnMap === null) {
1074  continue;
1075  }
1076  $propertyMetaData = $classSchema->getProperty($propertyName);
1077  if ($propertyMetaData['cascade'] === 'remove') {
1078  if ($columnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_MANY) {
1079  foreach ($propertyValue as $containedObject) {
1080  $this->removeEntity($containedObject);
1081  }
1082  } elseif ($propertyValue instanceof \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface) {
1083  $this->removeEntity($propertyValue);
1084  }
1085  } elseif ($dataMap->getDeletedFlagColumnName() === null
1086  && $columnMap->getTypeOfRelation() === ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY
1087  ) {
1088  $this->deleteAllRelationsFromRelationtable($object, $propertyName);
1089  }
1090  }
1091  }
1092 
1104  protected function determineStoragePageIdForNewRecord(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object = null)
1105  {
1106  $frameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
1107  if ($object !== null) {
1108  if (\TYPO3\CMS\Extbase\Reflection\ObjectAccess::isPropertyGettable($object, 'pid')) {
1110  if (isset($pid)) {
1111  return (int)$pid;
1112  }
1113  }
1114  $className = get_class($object);
1115  if (isset($frameworkConfiguration['persistence']['classes'][$className]) && !empty($frameworkConfiguration['persistence']['classes'][$className]['newRecordStoragePid'])) {
1116  return (int)$frameworkConfiguration['persistence']['classes'][$className]['newRecordStoragePid'];
1117  }
1118  }
1119  $storagePidList = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $frameworkConfiguration['persistence']['storagePid']);
1120  return (int)$storagePidList[0];
1121  }
1122 
1133  protected function getPlainValue($input, ColumnMap $columnMap = null)
1134  {
1135  return $input !== null
1136  ? $this->dataMapper->getPlainValue($input, $columnMap)
1137  : null;
1138  }
1139 }
setChangedEntities(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $entities)
Definition: Backend.php:319
emitBeforeGettingObjectDataSignal(\TYPO3\CMS\Extbase\Persistence\QueryInterface $query)
Definition: Backend.php:237
static intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
insertObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject=null, $parentPropertyName='')
Definition: Backend.php:648
emitEndInsertObjectSignal(DomainObjectInterface $object)
Definition: Backend.php:732
updateObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, array $row)
Definition: Backend.php:927
fetchMaxSortingFromParentTable(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $parentPropertyName)
Definition: Backend.php:872
updateRelationInRelationTable(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $propertyName, $sortingPosition=0)
Definition: Backend.php:795
emitAfterRemoveObjectSignal(DomainObjectInterface $object)
Definition: Backend.php:1055
emitAfterPersistObjectSignal(DomainObjectInterface $object)
Definition: Backend.php:964
addCommonFieldsToRow(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, array &$row)
Definition: Backend.php:975
determineStoragePageIdForNewRecord(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object=null)
Definition: Backend.php:1104
addCommonDateFieldsToRow(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, array &$row)
Definition: Backend.php:993
getObjectCountByQuery(\TYPO3\CMS\Extbase\Persistence\QueryInterface $query)
Definition: Backend.php:211
emitAfterInsertObjectSignal(DomainObjectInterface $object)
Definition: Backend.php:721
injectReflectionService(\TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService)
Definition: Backend.php:105
attachObjectToParentObjectRelationHasMany(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\AbstractEntity $parentObject, $parentPropertyName, $sortingPosition=0)
Definition: Backend.php:571
updateRelationOfObjectToParentObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\AbstractEntity $parentObject, $parentPropertyName, $sortingPosition=0)
Definition: Backend.php:551
detachObjectFromParentObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $parentPropertyName)
Definition: Backend.php:611
emitAfterUpdateObjectSignal(DomainObjectInterface $object)
Definition: Backend.php:954
static getProperty($subject, $propertyName, $forceDirectAccess=false)
insertRelationInRelationtable(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $propertyName, $sortingPosition=null)
Definition: Backend.php:757
getUidOfAlreadyPersistedValueObject(\TYPO3\CMS\Extbase\DomainObject\AbstractValueObject $object)
Definition: Backend.php:743
setAggregateRootObjects(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $objects)
Definition: Backend.php:309
static makeInstance($className,... $constructorArguments)
attachObjectToParentObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $parentPropertyName, $sortingPosition=0)
Definition: Backend.php:532
injectDataMapper(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper $dataMapper)
Definition: Backend.php:129
persistObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object)
Definition: Backend.php:366
getPlainValue($input, ColumnMap $columnMap=null)
Definition: Backend.php:1133
emitAfterGettingObjectDataSignal(\TYPO3\CMS\Extbase\Persistence\QueryInterface $query, array $result)
Definition: Backend.php:250
setDeletedEntities(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $entities)
Definition: Backend.php:329
injectSession(\TYPO3\CMS\Extbase\Persistence\Generic\Session $session)
Definition: Backend.php:97
injectSignalSlotDispatcher(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher)
Definition: Backend.php:137
removeEntity(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, $markAsDeleted=true)
Definition: Backend.php:1025
setPersistenceManager(\TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager)
Definition: Backend.php:159
__construct(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager)
Definition: Backend.php:147
getObjectDataByQuery(\TYPO3\CMS\Extbase\Persistence\QueryInterface $query)
Definition: Backend.php:223
removeRelatedObjects(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object)
Definition: Backend.php:1065
deleteRelationFromRelationtable(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $relatedObject, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $parentPropertyName)
Definition: Backend.php:847
deleteAllRelationsFromRelationtable(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $parentPropertyName)
Definition: Backend.php:823
getObjectByIdentifier($identifier, $className)
Definition: Backend.php:282
injectStorageBackend(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\BackendInterface $storageBackend)
Definition: Backend.php:121
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
injectQomFactory(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory)
Definition: Backend.php:113
getRemovedChildObjects(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, $propertyName)
Definition: Backend.php:509