TYPO3 CMS  TYPO3_7-6
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  } else {
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  }
293 
300  public function isNewObject($object)
301  {
302  return $this->getIdentifierByObject($object) === null;
303  }
304 
311  public function setAggregateRootObjects(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $objects)
312  {
313  $this->aggregateRootObjects = $objects;
314  }
315 
322  public function setChangedEntities(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $entities)
323  {
324  $this->changedEntities = $entities;
325  }
326 
333  public function setDeletedEntities(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $entities)
334  {
335  $this->deletedEntities = $entities;
336  }
337 
343  public function commit()
344  {
345  $this->persistObjects();
346  $this->processDeletedObjects();
347  }
348 
354  protected function persistObjects()
355  {
356  $this->visitedDuringPersistence = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
357  foreach ($this->aggregateRootObjects as $object) {
359  if ($object->_isNew()) {
360  $this->insertObject($object);
361  }
362  $this->persistObject($object, null);
363  }
364  foreach ($this->changedEntities as $object) {
365  $this->persistObject($object, null);
366  }
367  }
368 
375  protected function persistObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object)
376  {
377  if (isset($this->visitedDuringPersistence[$object])) {
378  return;
379  }
380  $row = [];
381  $queue = [];
382  $dataMap = $this->dataMapper->getDataMap(get_class($object));
383  $properties = $object->_getProperties();
384  foreach ($properties as $propertyName => $propertyValue) {
385  if (!$dataMap->isPersistableProperty($propertyName) || $this->propertyValueIsLazyLoaded($propertyValue)) {
386  continue;
387  }
388  $columnMap = $dataMap->getColumnMap($propertyName);
389  if ($propertyValue instanceof \TYPO3\CMS\Extbase\Persistence\ObjectStorage) {
390  $cleanProperty = $object->_getCleanProperty($propertyName);
391  // objectstorage needs to be persisted if the object is new, the objectstorge is dirty, meaning it has
392  // been changed after initial build, or an empty objectstorge is present and the cleanstate objectstorage
393  // has childelements, meaning all elements should been removed from the objectstorage
394  if ($object->_isNew() || $propertyValue->_isDirty() || ($propertyValue->count() === 0 && $cleanProperty && $cleanProperty->count() > 0)) {
395  $this->persistObjectStorage($propertyValue, $object, $propertyName, $row);
396  $propertyValue->_memorizeCleanState();
397  }
398  foreach ($propertyValue as $containedObject) {
399  if ($containedObject instanceof \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface) {
400  $queue[] = $containedObject;
401  }
402  }
403  } elseif ($propertyValue instanceof \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface
404  && $object instanceof ObjectMonitoringInterface) {
405  if ($object->_isDirty($propertyName)) {
406  if ($propertyValue->_isNew()) {
407  $this->insertObject($propertyValue, $object, $propertyName);
408  }
409  // Check explicitly for NULL, as getPlainValue would convert this to 'NULL'
410  $row[$columnMap->getColumnName()] = $propertyValue !== null
411  ? $this->dataMapper->getPlainValue($propertyValue)
412  : null;
413  }
414  $queue[] = $propertyValue;
415  } elseif ($object->_isNew() || $object->_isDirty($propertyName)) {
416  $row[$columnMap->getColumnName()] = $this->dataMapper->getPlainValue($propertyValue, $columnMap);
417  }
418  }
419  if (!empty($row)) {
420  $this->updateObject($object, $row);
421  $object->_memorizeCleanState();
422  }
423  $this->visitedDuringPersistence[$object] = $object->getUid();
424  foreach ($queue as $queuedObject) {
425  $this->persistObject($queuedObject);
426  }
427  $this->emitAfterPersistObjectSignal($object);
428  }
429 
436  protected function propertyValueIsLazyLoaded($propertyValue)
437  {
438  if ($propertyValue instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy) {
439  return true;
440  }
441  if ($propertyValue instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyObjectStorage) {
442  if ($propertyValue->isInitialized() === false) {
443  return true;
444  }
445  }
446  return false;
447  }
448 
460  protected function persistObjectStorage(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $objectStorage, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $propertyName, array &$row)
461  {
462  $className = get_class($parentObject);
463  $columnMap = $this->dataMapper->getDataMap($className)->getColumnMap($propertyName);
464  $propertyMetaData = $this->reflectionService->getClassSchema($className)->getProperty($propertyName);
465  foreach ($this->getRemovedChildObjects($parentObject, $propertyName) as $removedObject) {
466  $this->detachObjectFromParentObject($removedObject, $parentObject, $propertyName);
467  if ($columnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_MANY && $propertyMetaData['cascade'] === 'remove') {
468  $this->removeEntity($removedObject);
469  }
470  }
471 
472  $currentUids = [];
473  $sortingPosition = 1;
474  $updateSortingOfFollowing = false;
475 
476  foreach ($objectStorage as $object) {
478  if (empty($currentUids)) {
479  $sortingPosition = 1;
480  } else {
481  $sortingPosition++;
482  }
483  $cleanProperty = $parentObject->_getCleanProperty($propertyName);
484  if ($object->_isNew()) {
485  $this->insertObject($object);
486  $this->attachObjectToParentObject($object, $parentObject, $propertyName, $sortingPosition);
487  // if a new object is inserted, all objects after this need to have their sorting updated
488  $updateSortingOfFollowing = true;
489  } elseif ($cleanProperty === null || $cleanProperty->getPosition($object) === null) {
490  // if parent object is new then it doesn't have cleanProperty yet; before attaching object it's clean position is null
491  $this->attachObjectToParentObject($object, $parentObject, $propertyName, $sortingPosition);
492  // 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
493  $updateSortingOfFollowing = true;
494  } elseif ($objectStorage->isRelationDirty($object) || $cleanProperty->getPosition($object) !== $objectStorage->getPosition($object)) {
495  $this->updateRelationOfObjectToParentObject($object, $parentObject, $propertyName, $sortingPosition);
496  $updateSortingOfFollowing = true;
497  } elseif ($updateSortingOfFollowing) {
498  if ($sortingPosition > $objectStorage->getPosition($object)) {
499  $this->updateRelationOfObjectToParentObject($object, $parentObject, $propertyName, $sortingPosition);
500  } else {
501  $sortingPosition = $objectStorage->getPosition($object);
502  }
503  }
504  $currentUids[] = $object->getUid();
505  }
506 
507  if ($columnMap->getParentKeyFieldName() === null) {
508  $row[$columnMap->getColumnName()] = implode(',', $currentUids);
509  } else {
510  $row[$columnMap->getColumnName()] = $this->dataMapper->countRelated($parentObject, $propertyName);
511  }
512  }
513 
522  protected function getRemovedChildObjects(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, $propertyName)
523  {
524  $removedObjects = [];
525  $cleanPropertyValue = $object->_getCleanProperty($propertyName);
526  if (is_array($cleanPropertyValue) || $cleanPropertyValue instanceof \Iterator) {
527  $propertyValue = $object->_getProperty($propertyName);
528  foreach ($cleanPropertyValue as $containedObject) {
529  if (!$propertyValue->contains($containedObject)) {
530  $removedObjects[] = $containedObject;
531  }
532  }
533  }
534  return $removedObjects;
535  }
536 
546  protected function attachObjectToParentObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $parentPropertyName, $sortingPosition = 0)
547  {
548  $parentDataMap = $this->dataMapper->getDataMap(get_class($parentObject));
549  $parentColumnMap = $parentDataMap->getColumnMap($parentPropertyName);
550  if ($parentColumnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_MANY) {
551  $this->attachObjectToParentObjectRelationHasMany($object, $parentObject, $parentPropertyName, $sortingPosition);
552  } elseif ($parentColumnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
553  $this->insertRelationInRelationtable($object, $parentObject, $parentPropertyName, $sortingPosition);
554  }
555  }
556 
566  protected function updateRelationOfObjectToParentObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\AbstractEntity $parentObject, $parentPropertyName, $sortingPosition = 0)
567  {
568  $parentDataMap = $this->dataMapper->getDataMap(get_class($parentObject));
569  $parentColumnMap = $parentDataMap->getColumnMap($parentPropertyName);
570  if ($parentColumnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_MANY) {
571  $this->attachObjectToParentObjectRelationHasMany($object, $parentObject, $parentPropertyName, $sortingPosition);
572  } elseif ($parentColumnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
573  $this->updateRelationInRelationTable($object, $parentObject, $parentPropertyName, $sortingPosition);
574  }
575  }
576 
587  protected function attachObjectToParentObjectRelationHasMany(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\AbstractEntity $parentObject, $parentPropertyName, $sortingPosition = 0)
588  {
589  $parentDataMap = $this->dataMapper->getDataMap(get_class($parentObject));
590  $parentColumnMap = $parentDataMap->getColumnMap($parentPropertyName);
591  if ($parentColumnMap->getTypeOfRelation() !== \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_MANY) {
592  throw new \TYPO3\CMS\Extbase\Persistence\Exception\IllegalRelationTypeException(
593  'Parent column relation type is ' . $parentColumnMap->getTypeOfRelation() .
595  1345368105
596  );
597  }
598  $row = [];
599  $parentKeyFieldName = $parentColumnMap->getParentKeyFieldName();
600  if ($parentKeyFieldName !== null) {
601  $row[$parentKeyFieldName] = $parentObject->getUid();
602  $parentTableFieldName = $parentColumnMap->getParentTableFieldName();
603  if ($parentTableFieldName !== null) {
604  $row[$parentTableFieldName] = $parentDataMap->getTableName();
605  }
606  $relationTableMatchFields = $parentColumnMap->getRelationTableMatchFields();
607  if (is_array($relationTableMatchFields)) {
608  $row = array_merge($relationTableMatchFields, $row);
609  }
610  }
611  $childSortByFieldName = $parentColumnMap->getChildSortByFieldName();
612  if (!empty($childSortByFieldName)) {
613  $row[$childSortByFieldName] = $sortingPosition;
614  }
615  if (!empty($row)) {
616  $this->updateObject($object, $row);
617  }
618  }
619 
628  protected function detachObjectFromParentObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $parentPropertyName)
629  {
630  $parentDataMap = $this->dataMapper->getDataMap(get_class($parentObject));
631  $parentColumnMap = $parentDataMap->getColumnMap($parentPropertyName);
632  if ($parentColumnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_MANY) {
633  $row = [];
634  $parentKeyFieldName = $parentColumnMap->getParentKeyFieldName();
635  if ($parentKeyFieldName !== null) {
636  $row[$parentKeyFieldName] = 0;
637  $parentTableFieldName = $parentColumnMap->getParentTableFieldName();
638  if ($parentTableFieldName !== null) {
639  $row[$parentTableFieldName] = '';
640  }
641  $relationTableMatchFields = $parentColumnMap->getRelationTableMatchFields();
642  if (is_array($relationTableMatchFields) && !empty($relationTableMatchFields)) {
643  $row = array_merge(array_fill_keys(array_keys($relationTableMatchFields), ''), $row);
644  }
645  }
646  $childSortByFieldName = $parentColumnMap->getChildSortByFieldName();
647  if (!empty($childSortByFieldName)) {
648  $row[$childSortByFieldName] = 0;
649  }
650  if (!empty($row)) {
651  $this->updateObject($object, $row);
652  }
653  } elseif ($parentColumnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
654  $this->deleteRelationFromRelationtable($object, $parentObject, $parentPropertyName);
655  }
656  }
657 
666  protected function insertObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject = null, $parentPropertyName = '')
667  {
668  if ($object instanceof \TYPO3\CMS\Extbase\DomainObject\AbstractValueObject) {
669  $result = $this->getUidOfAlreadyPersistedValueObject($object);
670  if ($result !== false) {
671  $object->_setProperty('uid', (int)$result);
672  return;
673  }
674  }
675  $dataMap = $this->dataMapper->getDataMap(get_class($object));
676  $row = [];
677  $properties = $object->_getProperties();
678  foreach ($properties as $propertyName => $propertyValue) {
679  if (!$dataMap->isPersistableProperty($propertyName) || $this->propertyValueIsLazyLoaded($propertyValue)) {
680  continue;
681  }
682  $columnMap = $dataMap->getColumnMap($propertyName);
683  if ($columnMap->getTypeOfRelation() === ColumnMap::RELATION_HAS_ONE) {
684  $row[$columnMap->getColumnName()] = 0;
685  } elseif ($columnMap->getTypeOfRelation() !== ColumnMap::RELATION_NONE) {
686  if ($columnMap->getParentKeyFieldName() === null) {
687  // CSV type relation
688  $row[$columnMap->getColumnName()] = '';
689  } else {
690  // MM type relation
691  $row[$columnMap->getColumnName()] = 0;
692  }
693  } elseif ($propertyValue !== null) {
694  $row[$columnMap->getColumnName()] = $this->dataMapper->getPlainValue($propertyValue, $columnMap);
695  }
696  }
697  $this->addCommonFieldsToRow($object, $row);
698  if ($dataMap->getLanguageIdColumnName() !== null && $object->_getProperty('_languageUid') === null) {
699  $row[$dataMap->getLanguageIdColumnName()] = 0;
700  $object->_setProperty('_languageUid', 0);
701  }
702  if ($dataMap->getTranslationOriginColumnName() !== null) {
703  $row[$dataMap->getTranslationOriginColumnName()] = 0;
704  }
705  if ($dataMap->getTranslationOriginDiffSourceName() !== null) {
706  $row[$dataMap->getTranslationOriginDiffSourceName()] = '';
707  }
708  if ($parentObject !== null && $parentPropertyName) {
709  $parentColumnDataMap = $this->dataMapper->getDataMap(get_class($parentObject))->getColumnMap($parentPropertyName);
710  $relationTableMatchFields = $parentColumnDataMap->getRelationTableMatchFields();
711  if (is_array($relationTableMatchFields)) {
712  $row = array_merge($relationTableMatchFields, $row);
713  }
714  if ($parentColumnDataMap->getParentKeyFieldName() !== null) {
715  $row[$parentColumnDataMap->getParentKeyFieldName()] = (int)$parentObject->getUid();
716  }
717  }
718  $uid = $this->storageBackend->addRow($dataMap->getTableName(), $row);
719  $object->_setProperty('uid', (int)$uid);
720  $object->setPid((int)$row['pid']);
721  if ((int)$uid >= 1) {
722  $this->emitAfterInsertObjectSignal($object);
723  }
724  $frameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
725  if ($frameworkConfiguration['persistence']['updateReferenceIndex'] === '1') {
726  $this->referenceIndex->updateRefIndexTable($dataMap->getTableName(), $uid);
727  }
728  $this->session->registerObject($object, $uid);
729  if ((int)$uid >= 1) {
730  $this->emitEndInsertObjectSignal($object);
731  }
732  }
733 
740  {
741  $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterInsertObject', [$object]);
742  }
743 
751  {
752  $this->signalSlotDispatcher->dispatch(__CLASS__, 'endInsertObject', [$object]);
753  }
754 
761  protected function getUidOfAlreadyPersistedValueObject(\TYPO3\CMS\Extbase\DomainObject\AbstractValueObject $object)
762  {
763  return $this->storageBackend->getUidOfAlreadyPersistedValueObject($object);
764  }
765 
775  protected function insertRelationInRelationtable(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $propertyName, $sortingPosition = null)
776  {
777  $dataMap = $this->dataMapper->getDataMap(get_class($parentObject));
778  $columnMap = $dataMap->getColumnMap($propertyName);
779  $parentUid = $parentObject->getUid();
780  if ($parentObject->_getProperty('_localizedUid') !== null) {
781  $parentUid = $parentObject->_getProperty('_localizedUid');
782  }
783  $row = [
784  $columnMap->getParentKeyFieldName() => (int)$parentUid,
785  $columnMap->getChildKeyFieldName() => (int)$object->getUid(),
786  $columnMap->getChildSortByFieldName() => !is_null($sortingPosition) ? (int)$sortingPosition : 0
787  ];
788  $relationTableName = $columnMap->getRelationTableName();
789  if ($columnMap->getRelationTablePageIdColumnName() !== null) {
790  $row[$columnMap->getRelationTablePageIdColumnName()] = $this->determineStoragePageIdForNewRecord();
791  }
792  $relationTableMatchFields = $columnMap->getRelationTableMatchFields();
793  if (is_array($relationTableMatchFields)) {
794  $row = array_merge($relationTableMatchFields, $row);
795  }
796  $relationTableInsertFields = $columnMap->getRelationTableInsertFields();
797  if (is_array($relationTableInsertFields)) {
798  $row = array_merge($relationTableInsertFields, $row);
799  }
800  $res = $this->storageBackend->addRow($relationTableName, $row, true);
801  return $res;
802  }
803 
813  protected function updateRelationInRelationTable(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $propertyName, $sortingPosition = 0)
814  {
815  $dataMap = $this->dataMapper->getDataMap(get_class($parentObject));
816  $columnMap = $dataMap->getColumnMap($propertyName);
817  $row = [
818  $columnMap->getParentKeyFieldName() => (int)$parentObject->getUid(),
819  $columnMap->getChildKeyFieldName() => (int)$object->getUid(),
820  $columnMap->getChildSortByFieldName() => (int)$sortingPosition
821  ];
822  $relationTableName = $columnMap->getRelationTableName();
823  $relationTableMatchFields = $columnMap->getRelationTableMatchFields();
824  if (is_array($relationTableMatchFields)) {
825  $row = array_merge($relationTableMatchFields, $row);
826  }
827  $res = $this->storageBackend->updateRelationTableRow(
828  $relationTableName,
829  $row);
830  return $res;
831  }
832 
840  protected function deleteAllRelationsFromRelationtable(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $parentPropertyName)
841  {
842  $dataMap = $this->dataMapper->getDataMap(get_class($parentObject));
843  $columnMap = $dataMap->getColumnMap($parentPropertyName);
844  $relationTableName = $columnMap->getRelationTableName();
845  $relationMatchFields = [
846  $columnMap->getParentKeyFieldName() => (int)$parentObject->getUid()
847  ];
848  $relationTableMatchFields = $columnMap->getRelationTableMatchFields();
849  if (is_array($relationTableMatchFields)) {
850  $relationMatchFields = array_merge($relationTableMatchFields, $relationMatchFields);
851  }
852  $res = $this->storageBackend->removeRow($relationTableName, $relationMatchFields, false);
853  return $res;
854  }
855 
864  protected function deleteRelationFromRelationtable(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $relatedObject, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $parentPropertyName)
865  {
866  $dataMap = $this->dataMapper->getDataMap(get_class($parentObject));
867  $columnMap = $dataMap->getColumnMap($parentPropertyName);
868  $relationTableName = $columnMap->getRelationTableName();
869  $relationMatchFields = [
870  $columnMap->getParentKeyFieldName() => (int)$parentObject->getUid(),
871  $columnMap->getChildKeyFieldName() => (int)$relatedObject->getUid()
872  ];
873  $relationTableMatchFields = $columnMap->getRelationTableMatchFields();
874  if (is_array($relationTableMatchFields)) {
875  $relationMatchFields = array_merge($relationTableMatchFields, $relationMatchFields);
876  }
877  $res = $this->storageBackend->removeRow($relationTableName, $relationMatchFields, false);
878  return $res;
879  }
880 
889  protected function fetchMaxSortingFromParentTable(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $parentPropertyName)
890  {
891  $parentDataMap = $this->dataMapper->getDataMap(get_class($parentObject));
892  $parentColumnMap = $parentDataMap->getColumnMap($parentPropertyName);
893  if ($parentColumnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_MANY) {
894  $tableName = $parentColumnMap->getChildTableName();
895  $sortByFieldName = $parentColumnMap->getChildSortByFieldName();
896 
897  if (empty($sortByFieldName)) {
898  return false;
899  }
900  $matchFields = [];
901  $parentKeyFieldName = $parentColumnMap->getParentKeyFieldName();
902  if ($parentKeyFieldName !== null) {
903  $matchFields[$parentKeyFieldName] = $parentObject->getUid();
904  $parentTableFieldName = $parentColumnMap->getParentTableFieldName();
905  if ($parentTableFieldName !== null) {
906  $matchFields[$parentTableFieldName] = $parentDataMap->getTableName();
907  }
908  }
909 
910  if (empty($matchFields)) {
911  return false;
912  }
913  } elseif ($parentColumnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
914  $tableName = $parentColumnMap->getRelationTableName();
915  $sortByFieldName = $parentColumnMap->getChildSortByFieldName();
916 
917  $matchFields = [
918  $parentColumnMap->getParentKeyFieldName() => (int)$parentObject->getUid()
919  ];
920 
921  $relationTableMatchFields = $parentColumnMap->getRelationTableMatchFields();
922  if (is_array($relationTableMatchFields)) {
923  $matchFields = array_merge($relationTableMatchFields, $matchFields);
924  }
925  } else {
926  throw new \TYPO3\CMS\Extbase\Persistence\Exception\IllegalRelationTypeException('Unexpected parent column relation type: ' . $parentColumnMap->getTypeOfRelation(), 1345368106);
927  }
928 
929  $result = $this->storageBackend->getMaxValueFromTable(
930  $tableName,
931  $matchFields,
932  $sortByFieldName);
933  return $result;
934  }
935 
943  protected function updateObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, array $row)
944  {
945  $dataMap = $this->dataMapper->getDataMap(get_class($object));
946  $this->addCommonFieldsToRow($object, $row);
947  $row['uid'] = $object->getUid();
948  if ($dataMap->getLanguageIdColumnName() !== null) {
949  $row[$dataMap->getLanguageIdColumnName()] = (int)$object->_getProperty('_languageUid');
950  if ($object->_getProperty('_localizedUid') !== null) {
951  $row['uid'] = $object->_getProperty('_localizedUid');
952  }
953  }
954  $res = $this->storageBackend->updateRow($dataMap->getTableName(), $row);
955  if ($res === true) {
956  $this->emitAfterUpdateObjectSignal($object);
957  }
958  $frameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
959  if ($frameworkConfiguration['persistence']['updateReferenceIndex'] === '1') {
960  $this->referenceIndex->updateRefIndexTable($dataMap->getTableName(), $row['uid']);
961  }
962  return $res;
963  }
964 
971  {
972  $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterUpdateObject', [$object]);
973  }
974 
981  {
982  $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterPersistObject', [$object]);
983  }
984 
992  protected function addCommonFieldsToRow(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, array &$row)
993  {
994  $dataMap = $this->dataMapper->getDataMap(get_class($object));
995  $this->addCommonDateFieldsToRow($object, $row);
996  if ($dataMap->getRecordTypeColumnName() !== null && $dataMap->getRecordType() !== null) {
997  $row[$dataMap->getRecordTypeColumnName()] = $dataMap->getRecordType();
998  }
999  if ($object->_isNew() && !isset($row['pid'])) {
1000  $row['pid'] = $this->determineStoragePageIdForNewRecord($object);
1001  }
1002  }
1003 
1011  protected function addCommonDateFieldsToRow(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, array &$row)
1012  {
1013  $dataMap = $this->dataMapper->getDataMap(get_class($object));
1014  if ($object->_isNew() && $dataMap->getCreationDateColumnName() !== null) {
1015  $row[$dataMap->getCreationDateColumnName()] = $GLOBALS['EXEC_TIME'];
1016  }
1017  if ($dataMap->getModificationDateColumnName() !== null) {
1018  $row[$dataMap->getModificationDateColumnName()] = $GLOBALS['EXEC_TIME'];
1019  }
1020  }
1021 
1027  protected function processDeletedObjects()
1028  {
1029  foreach ($this->deletedEntities as $entity) {
1030  if ($this->session->hasObject($entity)) {
1031  $this->removeEntity($entity);
1032  $this->session->unregisterReconstitutedEntity($entity);
1033  $this->session->unregisterObject($entity);
1034  }
1035  }
1036  $this->deletedEntities = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
1037  }
1038 
1046  protected function removeEntity(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, $markAsDeleted = true)
1047  {
1048  $dataMap = $this->dataMapper->getDataMap(get_class($object));
1049  $tableName = $dataMap->getTableName();
1050  if ($markAsDeleted === true && $dataMap->getDeletedFlagColumnName() !== null) {
1051  $deletedColumnName = $dataMap->getDeletedFlagColumnName();
1052  $row = [
1053  'uid' => $object->getUid(),
1054  $deletedColumnName => 1
1055  ];
1056  $this->addCommonDateFieldsToRow($object, $row);
1057  $res = $this->storageBackend->updateRow($tableName, $row);
1058  } else {
1059  $res = $this->storageBackend->removeRow($tableName, ['uid' => $object->getUid()]);
1060  }
1061  if ($res === true) {
1062  $this->emitAfterRemoveObjectSignal($object);
1063  }
1064  $this->removeRelatedObjects($object);
1065  $frameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
1066  if ($frameworkConfiguration['persistence']['updateReferenceIndex'] === '1') {
1067  $this->referenceIndex->updateRefIndexTable($tableName, $object->getUid());
1068  }
1069  }
1070 
1077  {
1078  $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterRemoveObject', [$object]);
1079  }
1080 
1087  protected function removeRelatedObjects(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object)
1088  {
1089  $className = get_class($object);
1090  $dataMap = $this->dataMapper->getDataMap($className);
1091  $classSchema = $this->reflectionService->getClassSchema($className);
1092  $properties = $object->_getProperties();
1093  foreach ($properties as $propertyName => $propertyValue) {
1094  $columnMap = $dataMap->getColumnMap($propertyName);
1095  if ($columnMap === null) {
1096  continue;
1097  }
1098  $propertyMetaData = $classSchema->getProperty($propertyName);
1099  if ($propertyMetaData['cascade'] === 'remove') {
1100  if ($columnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_MANY) {
1101  foreach ($propertyValue as $containedObject) {
1102  $this->removeEntity($containedObject);
1103  }
1104  } elseif ($propertyValue instanceof \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface) {
1105  $this->removeEntity($propertyValue);
1106  }
1107  } elseif ($dataMap->getDeletedFlagColumnName() === null
1108  && $columnMap->getTypeOfRelation() === ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY
1109  ) {
1110  $this->deleteAllRelationsFromRelationtable($object, $propertyName);
1111  }
1112  }
1113  }
1114 
1126  protected function determineStoragePageIdForNewRecord(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object = null)
1127  {
1128  $frameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
1129  if ($object !== null) {
1130  if (\TYPO3\CMS\Extbase\Reflection\ObjectAccess::isPropertyGettable($object, 'pid')) {
1132  if (isset($pid)) {
1133  return (int)$pid;
1134  }
1135  }
1136  $className = get_class($object);
1137  if (isset($frameworkConfiguration['persistence']['classes'][$className]) && !empty($frameworkConfiguration['persistence']['classes'][$className]['newRecordStoragePid'])) {
1138  return (int)$frameworkConfiguration['persistence']['classes'][$className]['newRecordStoragePid'];
1139  }
1140  }
1141  $storagePidList = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $frameworkConfiguration['persistence']['storagePid']);
1142  return (int)$storagePidList[0];
1143  }
1144 }
setChangedEntities(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $entities)
Definition: Backend.php:322
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:666
emitEndInsertObjectSignal(DomainObjectInterface $object)
Definition: Backend.php:750
updateObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, array $row)
Definition: Backend.php:943
fetchMaxSortingFromParentTable(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $parentPropertyName)
Definition: Backend.php:889
updateRelationInRelationTable(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $propertyName, $sortingPosition=0)
Definition: Backend.php:813
emitAfterRemoveObjectSignal(DomainObjectInterface $object)
Definition: Backend.php:1076
emitAfterPersistObjectSignal(DomainObjectInterface $object)
Definition: Backend.php:980
addCommonFieldsToRow(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, array &$row)
Definition: Backend.php:992
determineStoragePageIdForNewRecord(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object=null)
Definition: Backend.php:1126
addCommonDateFieldsToRow(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, array &$row)
Definition: Backend.php:1011
getObjectCountByQuery(\TYPO3\CMS\Extbase\Persistence\QueryInterface $query)
Definition: Backend.php:211
emitAfterInsertObjectSignal(DomainObjectInterface $object)
Definition: Backend.php:739
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:587
updateRelationOfObjectToParentObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\AbstractEntity $parentObject, $parentPropertyName, $sortingPosition=0)
Definition: Backend.php:566
detachObjectFromParentObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $parentPropertyName)
Definition: Backend.php:628
emitAfterUpdateObjectSignal(DomainObjectInterface $object)
Definition: Backend.php:970
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:775
getUidOfAlreadyPersistedValueObject(\TYPO3\CMS\Extbase\DomainObject\AbstractValueObject $object)
Definition: Backend.php:761
setAggregateRootObjects(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $objects)
Definition: Backend.php:311
attachObjectToParentObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $parentPropertyName, $sortingPosition=0)
Definition: Backend.php:546
injectDataMapper(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper $dataMapper)
Definition: Backend.php:129
persistObject(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object)
Definition: Backend.php:375
emitAfterGettingObjectDataSignal(\TYPO3\CMS\Extbase\Persistence\QueryInterface $query, array $result)
Definition: Backend.php:250
setDeletedEntities(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $entities)
Definition: Backend.php:333
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:1046
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:1087
deleteRelationFromRelationtable(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $relatedObject, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $parentPropertyName)
Definition: Backend.php:864
$uid
Definition: server.php:38
deleteAllRelationsFromRelationtable(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $parentPropertyName)
Definition: Backend.php:840
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:522