TYPO3 CMS  TYPO3_8-7
DataMapFactory.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 
21 {
25  protected $reflectionService;
26 
31 
35  protected $objectManager;
36 
40  protected $cacheManager;
41 
45  protected $dataMapCache;
46 
50  public function injectReflectionService(\TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService)
51  {
52  $this->reflectionService = $reflectionService;
53  }
54 
59  {
60  $this->configurationManager = $configurationManager;
61  }
62 
66  public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
67  {
68  $this->objectManager = $objectManager;
69  }
70 
74  public function injectCacheManager(\TYPO3\CMS\Core\Cache\CacheManager $cacheManager)
75  {
76  $this->cacheManager = $cacheManager;
77  }
78 
82  public function initializeObject()
83  {
84  $this->dataMapCache = $this->cacheManager->getCache('extbase_datamapfactory_datamap');
85  }
86 
95  public function buildDataMap($className)
96  {
97  $dataMap = $this->dataMapCache->get(str_replace('\\', '%', $className));
98  if ($dataMap === false) {
99  $dataMap = $this->buildDataMapInternal($className);
100  $this->dataMapCache->set(str_replace('\\', '%', $className), $dataMap);
101  }
102  return $dataMap;
103  }
104 
114  protected function buildDataMapInternal($className)
115  {
116  if (!class_exists($className)) {
117  throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\InvalidClassException(
118  'Could not find class definition for name "' . $className . '". This could be caused by a mis-spelling of the class name in the class definition.',
119  1476045117
120  );
121  }
122  $recordType = null;
123  $subclasses = [];
124  $tableName = $this->resolveTableName($className);
125  $columnMapping = [];
126  $frameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
127  $classSettings = $frameworkConfiguration['persistence']['classes'][$className];
128  if ($classSettings !== null) {
129  if (isset($classSettings['subclasses']) && is_array($classSettings['subclasses'])) {
130  $subclasses = $this->resolveSubclassesRecursive($frameworkConfiguration['persistence']['classes'], $classSettings['subclasses']);
131  }
132  if (isset($classSettings['mapping']['recordType']) && $classSettings['mapping']['recordType'] !== '') {
133  $recordType = $classSettings['mapping']['recordType'];
134  }
135  if (isset($classSettings['mapping']['tableName']) && $classSettings['mapping']['tableName'] !== '') {
136  $tableName = $classSettings['mapping']['tableName'];
137  }
138  $classHierarchy = array_merge([$className], class_parents($className));
139  foreach ($classHierarchy as $currentClassName) {
140  if (in_array($currentClassName, [\TYPO3\CMS\Extbase\DomainObject\AbstractEntity::class, \TYPO3\CMS\Extbase\DomainObject\AbstractValueObject::class])) {
141  break;
142  }
143  $currentClassSettings = $frameworkConfiguration['persistence']['classes'][$currentClassName];
144  if ($currentClassSettings !== null) {
145  if (isset($currentClassSettings['mapping']['columns']) && is_array($currentClassSettings['mapping']['columns'])) {
146  \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($columnMapping, $currentClassSettings['mapping']['columns'], true, false);
147  }
148  }
149  }
150  }
152  $dataMap = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMap::class, $className, $tableName, $recordType, $subclasses);
153  $dataMap = $this->addMetaDataColumnNames($dataMap, $tableName);
154  // $classPropertyNames = $this->reflectionService->getClassPropertyNames($className);
155  $tcaColumnsDefinition = $this->getColumnsDefinition($tableName);
156  \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($tcaColumnsDefinition, $columnMapping);
157  // @todo Is this is too powerful?
158 
159  foreach ($tcaColumnsDefinition as $columnName => $columnDefinition) {
160  if (isset($columnDefinition['mapOnProperty'])) {
161  $propertyName = $columnDefinition['mapOnProperty'];
162  } else {
164  }
165  // if (in_array($propertyName, $classPropertyNames)) {
166  // @todo Enable check for property existence
167  $columnMap = $this->createColumnMap($columnName, $propertyName);
168  $propertyMetaData = $this->reflectionService->getClassSchema($className)->getProperty($propertyName);
169  $columnMap = $this->setType($columnMap, $columnDefinition['config']);
170  $columnMap = $this->setRelations($columnMap, $columnDefinition['config'], $propertyMetaData);
171  $columnMap = $this->setFieldEvaluations($columnMap, $columnDefinition['config']);
172  $dataMap->addColumnMap($columnMap);
173  }
174  return $dataMap;
175  }
176 
183  protected function resolveTableName($className)
184  {
185  $className = ltrim($className, '\\');
186  if (strpos($className, '\\') !== false) {
187  $classNameParts = explode('\\', $className);
188  // Skip vendor and product name for core classes
189  if (strpos($className, 'TYPO3\\CMS\\') === 0) {
190  $classPartsToSkip = 2;
191  } else {
192  $classPartsToSkip = 1;
193  }
194  $tableName = 'tx_' . strtolower(implode('_', array_slice($classNameParts, $classPartsToSkip)));
195  } else {
196  $tableName = strtolower($className);
197  }
198  return $tableName;
199  }
200 
209  protected function resolveSubclassesRecursive(array $classesConfiguration, array $subclasses)
210  {
211  $allSubclasses = [];
212  foreach ($subclasses as $subclass) {
213  $allSubclasses[] = $subclass;
214  if (isset($classesConfiguration[$subclass]['subclasses']) && is_array($classesConfiguration[$subclass]['subclasses'])) {
215  $childSubclasses = $this->resolveSubclassesRecursive($classesConfiguration, $classesConfiguration[$subclass]['subclasses']);
216  $allSubclasses = array_merge($allSubclasses, $childSubclasses);
217  }
218  }
219  return $allSubclasses;
220  }
221 
228  protected function getControlSection($tableName)
229  {
230  return is_array($GLOBALS['TCA'][$tableName]['ctrl']) ? $GLOBALS['TCA'][$tableName]['ctrl'] : null;
231  }
232 
239  protected function getColumnsDefinition($tableName)
240  {
241  return is_array($GLOBALS['TCA'][$tableName]['columns']) ? $GLOBALS['TCA'][$tableName]['columns'] : [];
242  }
243 
249  protected function addMetaDataColumnNames(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMap $dataMap, $tableName)
250  {
251  $controlSection = $GLOBALS['TCA'][$tableName]['ctrl'];
252  $dataMap->setPageIdColumnName('pid');
253  if (isset($controlSection['tstamp'])) {
254  $dataMap->setModificationDateColumnName($controlSection['tstamp']);
255  }
256  if (isset($controlSection['crdate'])) {
257  $dataMap->setCreationDateColumnName($controlSection['crdate']);
258  }
259  if (isset($controlSection['cruser_id'])) {
260  $dataMap->setCreatorColumnName($controlSection['cruser_id']);
261  }
262  if (isset($controlSection['delete'])) {
263  $dataMap->setDeletedFlagColumnName($controlSection['delete']);
264  }
265  if (isset($controlSection['languageField'])) {
266  $dataMap->setLanguageIdColumnName($controlSection['languageField']);
267  }
268  if (isset($controlSection['transOrigPointerField'])) {
269  $dataMap->setTranslationOriginColumnName($controlSection['transOrigPointerField']);
270  }
271  if (isset($controlSection['transOrigDiffSourceField'])) {
272  $dataMap->setTranslationOriginDiffSourceName($controlSection['transOrigDiffSourceField']);
273  }
274  if (isset($controlSection['type'])) {
275  $dataMap->setRecordTypeColumnName($controlSection['type']);
276  }
277  if (isset($controlSection['rootLevel'])) {
278  $dataMap->setRootLevel($controlSection['rootLevel']);
279  }
280  if (isset($controlSection['is_static'])) {
281  $dataMap->setIsStatic($controlSection['is_static']);
282  }
283  if (isset($controlSection['enablecolumns']['disabled'])) {
284  $dataMap->setDisabledFlagColumnName($controlSection['enablecolumns']['disabled']);
285  }
286  if (isset($controlSection['enablecolumns']['starttime'])) {
287  $dataMap->setStartTimeColumnName($controlSection['enablecolumns']['starttime']);
288  }
289  if (isset($controlSection['enablecolumns']['endtime'])) {
290  $dataMap->setEndTimeColumnName($controlSection['enablecolumns']['endtime']);
291  }
292  if (isset($controlSection['enablecolumns']['fe_group'])) {
293  $dataMap->setFrontEndUserGroupColumnName($controlSection['enablecolumns']['fe_group']);
294  }
295  return $dataMap;
296  }
297 
305  protected function setType(ColumnMap $columnMap, $columnConfiguration)
306  {
307  $tableColumnType = (isset($columnConfiguration['type'])) ? $columnConfiguration['type'] : null;
308  $columnMap->setType(\TYPO3\CMS\Core\DataHandling\TableColumnType::cast($tableColumnType));
309  $tableColumnSubType = (isset($columnConfiguration['internal_type'])) ? $columnConfiguration['internal_type'] : null;
310  $columnMap->setInternalType(\TYPO3\CMS\Core\DataHandling\TableColumnSubType::cast($tableColumnSubType));
311 
312  return $columnMap;
313  }
314 
324  protected function setRelations(ColumnMap $columnMap, $columnConfiguration, $propertyMetaData)
325  {
326  if (isset($columnConfiguration)) {
327  if (isset($columnConfiguration['MM'])) {
328  $columnMap = $this->setManyToManyRelation($columnMap, $columnConfiguration);
329  } elseif (isset($propertyMetaData['elementType'])) {
330  $columnMap = $this->setOneToManyRelation($columnMap, $columnConfiguration);
331  } elseif (isset($propertyMetaData['type']) && strpbrk($propertyMetaData['type'], '_\\') !== false) {
332  $columnMap = $this->setOneToOneRelation($columnMap, $columnConfiguration);
333  } elseif (
334  isset($columnConfiguration['type'], $columnConfiguration['renderType'])
335  && $columnConfiguration['type'] === 'select'
336  && (
337  $columnConfiguration['renderType'] !== 'selectSingle'
338  || (isset($columnConfiguration['maxitems']) && $columnConfiguration['maxitems'] > 1)
339  )
340  ) {
342  } elseif (
343  isset($columnConfiguration['type']) && $columnConfiguration['type'] === 'group'
344  && (!isset($columnConfiguration['maxitems']) || $columnConfiguration['maxitems'] > 1)
345  ) {
347  } else {
349  }
350  } else {
352  }
353  return $columnMap;
354  }
355 
363  protected function setFieldEvaluations(ColumnMap $columnMap, array $columnConfiguration = null)
364  {
365  if (!empty($columnConfiguration['eval'])) {
366  $fieldEvaluations = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $columnConfiguration['eval'], true);
367  $dateTimeEvaluations = ['date', 'datetime'];
368 
369  if (!empty(array_intersect($dateTimeEvaluations, $fieldEvaluations)) && !empty($columnConfiguration['dbType'])) {
370  $columnMap->setDateTimeStorageFormat($columnConfiguration['dbType']);
371  }
372  }
373 
374  return $columnMap;
375  }
376 
385  protected function setOneToOneRelation(ColumnMap $columnMap, array $columnConfiguration = null)
386  {
388  $columnMap->setChildTableName($columnConfiguration['foreign_table']);
389  $columnMap->setChildTableWhereStatement($columnConfiguration['foreign_table_where']);
390  $columnMap->setChildSortByFieldName($columnConfiguration['foreign_sortby']);
391  $columnMap->setParentKeyFieldName($columnConfiguration['foreign_field']);
392  $columnMap->setParentTableFieldName($columnConfiguration['foreign_table_field']);
393  if (is_array($columnConfiguration['foreign_match_fields'])) {
394  $columnMap->setRelationTableMatchFields($columnConfiguration['foreign_match_fields']);
395  }
396  return $columnMap;
397  }
398 
407  protected function setOneToManyRelation(ColumnMap $columnMap, array $columnConfiguration = null)
408  {
410  $columnMap->setChildTableName($columnConfiguration['foreign_table']);
411  $columnMap->setChildTableWhereStatement($columnConfiguration['foreign_table_where']);
412  $columnMap->setChildSortByFieldName($columnConfiguration['foreign_sortby']);
413  $columnMap->setParentKeyFieldName($columnConfiguration['foreign_field']);
414  $columnMap->setParentTableFieldName($columnConfiguration['foreign_table_field']);
415  if (is_array($columnConfiguration['foreign_match_fields'])) {
416  $columnMap->setRelationTableMatchFields($columnConfiguration['foreign_match_fields']);
417  }
418  return $columnMap;
419  }
420 
430  protected function setManyToManyRelation(ColumnMap $columnMap, array $columnConfiguration = null)
431  {
432  if (isset($columnConfiguration['MM'])) {
434  $columnMap->setChildTableName($columnConfiguration['foreign_table']);
435  $columnMap->setChildTableWhereStatement($columnConfiguration['foreign_table_where']);
436  $columnMap->setRelationTableName($columnConfiguration['MM']);
437  if (is_array($columnConfiguration['MM_match_fields'])) {
438  $columnMap->setRelationTableMatchFields($columnConfiguration['MM_match_fields']);
439  }
440  if (is_array($columnConfiguration['MM_insert_fields'])) {
441  $columnMap->setRelationTableInsertFields($columnConfiguration['MM_insert_fields']);
442  }
443  $columnMap->setRelationTableWhereStatement($columnConfiguration['MM_table_where']);
444  if (!empty($columnConfiguration['MM_opposite_field'])) {
445  $columnMap->setParentKeyFieldName('uid_foreign');
446  $columnMap->setChildKeyFieldName('uid_local');
447  $columnMap->setChildSortByFieldName('sorting_foreign');
448  } else {
449  $columnMap->setParentKeyFieldName('uid_local');
450  $columnMap->setChildKeyFieldName('uid_foreign');
451  $columnMap->setChildSortByFieldName('sorting');
452  }
453  } else {
454  throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnsupportedRelationException('The given information to build a many-to-many-relation was not sufficient. Check your TCA definitions. mm-relations with IRRE must have at least a defined "MM" or "foreign_selector".', 1268817963);
455  }
456  if ($this->getControlSection($columnMap->getRelationTableName()) !== null) {
457  $columnMap->setRelationTablePageIdColumnName('pid');
458  }
459  return $columnMap;
460  }
461 
470  protected function createColumnMap($columnName, $propertyName)
471  {
472  return $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::class, $columnName, $propertyName);
473  }
474 }
setRelationTablePageIdColumnName($relationTablePageIdColumnName)
Definition: ColumnMap.php:299
injectConfigurationManager(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager)
injectCacheManager(\TYPO3\CMS\Core\Cache\CacheManager $cacheManager)
resolveSubclassesRecursive(array $classesConfiguration, array $subclasses)
setFieldEvaluations(ColumnMap $columnMap, array $columnConfiguration=null)
setManyToManyRelation(ColumnMap $columnMap, array $columnConfiguration=null)
setRelationTableMatchFields(array $relationTableMatchFields)
Definition: ColumnMap.php:315
injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
setOneToOneRelation(ColumnMap $columnMap, array $columnConfiguration=null)
addMetaDataColumnNames(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMap $dataMap, $tableName)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
setRelationTableWhereStatement($relationTableWhereStatement)
Definition: ColumnMap.php:347
setRelationTableInsertFields(array $relationTableInsertFields)
Definition: ColumnMap.php:331
injectReflectionService(\TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService)
setChildTableWhereStatement($childTableWhereStatement)
Definition: ColumnMap.php:251
setOneToManyRelation(ColumnMap $columnMap, array $columnConfiguration=null)
static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
setRelations(ColumnMap $columnMap, $columnConfiguration, $propertyMetaData)
setType(ColumnMap $columnMap, $columnConfiguration)