‪TYPO3CMS  ‪main
ColumnMapFactory.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
28 
33 {
34  public function ‪__construct(
35  private readonly ‪ReflectionService $reflectionService
36  ) {}
37 
38  public function ‪create(string $columnName, array $columnDefinition, string $propertyName, string $className): ‪ColumnMap
39  {
40  $columnMap = GeneralUtility::makeInstance(ColumnMap::class, $columnName);
41  try {
42  $property = $this->reflectionService->getClassSchema($className)->getProperty($propertyName);
43  $nonProxyPropertyTypes = $property->getFilteredTypes([$property, 'filterLazyLoadingProxyAndLazyObjectStorage']);
44 
45  if ($nonProxyPropertyTypes === []) {
46  throw ‪NoPropertyTypesException::create($className, $propertyName);
47  }
48 
49  $primaryType = $nonProxyPropertyTypes[0];
50  $type = $primaryType->getClassName() ?? $primaryType->getBuiltinType();
51 
52  $collectionValueType = null;
53  if ($primaryType->isCollection() && $primaryType->getCollectionValueTypes() !== []) {
54  $primaryCollectionValueType = $primaryType->getCollectionValueTypes()[0];
55  $collectionValueType = $primaryCollectionValueType->getClassName() ?? $primaryCollectionValueType->getBuiltinType();
56  }
57 
58  [$type, $elementType] = [$type, $collectionValueType];
60  [$type, $elementType] = [null, null];
61  }
62  $columnMap = $this->‪setType($columnMap, $columnDefinition['config']);
63  $columnMap = $this->‪setRelations($columnMap, $columnDefinition['config'], $type, $elementType);
64  return $this->‪setDateTimeStorageFormat($columnMap, $columnDefinition['config']);
65  }
66 
70  protected function ‪setType(‪ColumnMap $columnMap, array $columnConfiguration): ‪ColumnMap
71  {
72  // todo: this method should only be called with proper arguments which means that the TCA integrity check should
73  // todo: take place outside this method.
74 
75  $tableColumnType = $columnConfiguration['type'] ?? null;
76  $columnMap->‪setType(TableColumnType::tryFrom($tableColumnType) ?? TableColumnType::INPUT);
77  return $columnMap;
78  }
79 
87  protected function ‪setRelations(‪ColumnMap $columnMap, ?array $columnConfiguration, ?string $type, ?string $elementType): ‪ColumnMap
88  {
89  if (!isset($columnConfiguration)) {
90  return $columnMap;
91  }
92 
93  if (isset($columnConfiguration['MM'])) {
94  return $this->‪setManyToManyRelation($columnMap, $columnConfiguration);
95  }
96 
97  if ($elementType !== null) {
98  return $this->‪setOneToManyRelation($columnMap, $columnConfiguration);
99  }
100 
101  if ($type !== null && strpbrk($type, '_\\') !== false) {
102  // @todo: check the strpbrk function call. Seems to be a check for Tx_Foo_Bar style class names
103  return $this->‪setOneToOneRelation($columnMap, $columnConfiguration);
104  }
105 
106  if (
107  isset($columnConfiguration['type'], $columnConfiguration['renderType'])
108  && $columnConfiguration['type'] === 'select'
109  && (
110  $columnConfiguration['renderType'] !== 'selectSingle'
111  || (isset($columnConfiguration['maxitems']) && $columnConfiguration['maxitems'] > 1)
112  )
113  ) {
114  $columnMap->‪setTypeOfRelation(Relation::HAS_MANY);
115  return $columnMap;
116  }
117 
118  if (
119  isset($columnConfiguration['type']) && ($columnConfiguration['type'] === 'group' || $columnConfiguration['type'] === 'folder')
120  && (!isset($columnConfiguration['maxitems']) || $columnConfiguration['maxitems'] > 1)
121  ) {
122  $columnMap->‪setTypeOfRelation(Relation::HAS_MANY);
123  return $columnMap;
124  }
125 
126  return $columnMap;
127  }
128 
135  protected function ‪setDateTimeStorageFormat(‪ColumnMap $columnMap, array $columnConfiguration = null): ‪ColumnMap
136  {
137  // todo: this method should only be called with proper arguments which means that the TCA integrity check should
138  // todo: take place outside this method.
139 
140  if ($columnMap->‪getType() === TableColumnType::DATETIME
141  && in_array($columnConfiguration['dbType'] ?? '', ‪QueryHelper::getDateTimeTypes(), true)
142  ) {
143  $columnMap->‪setDateTimeStorageFormat($columnConfiguration['dbType']);
144  }
145 
146  return $columnMap;
147  }
148 
156  protected function ‪setOneToOneRelation(‪ColumnMap $columnMap, array $columnConfiguration = null): ‪ColumnMap
157  {
158  // todo: this method should only be called with proper arguments which means that the TCA integrity check should
159  // todo: take place outside this method.
160 
161  $columnMap->‪setTypeOfRelation(Relation::HAS_ONE);
162  // check if foreign_table is set, which usually won't be the case for type "group" fields
163  if (!empty($columnConfiguration['foreign_table'])) {
164  $columnMap->‪setChildTableName($columnConfiguration['foreign_table']);
165  }
166  // todo: don't update column map if value(s) isn't/aren't set.
167  $columnMap->‪setChildSortByFieldName($columnConfiguration['foreign_sortby'] ?? null);
168  $columnMap->‪setParentKeyFieldName($columnConfiguration['foreign_field'] ?? null);
169  $columnMap->‪setParentTableFieldName($columnConfiguration['foreign_table_field'] ?? null);
170  if (isset($columnConfiguration['foreign_match_fields']) && is_array($columnConfiguration['foreign_match_fields'])) {
171  $columnMap->‪setRelationTableMatchFields($columnConfiguration['foreign_match_fields']);
172  }
173  return $columnMap;
174  }
175 
185  public function ‪setOneToManyRelation(‪ColumnMap $columnMap, array $columnConfiguration = null): ‪ColumnMap
186  {
187  // todo: this method should only be called with proper arguments which means that the TCA integrity check should
188  // todo: take place outside this method.
189 
190  $columnMap->‪setTypeOfRelation(Relation::HAS_MANY);
191  // check if foreign_table is set, which usually won't be the case for type "group" fields
192  if (!empty($columnConfiguration['foreign_table'])) {
193  $columnMap->‪setChildTableName($columnConfiguration['foreign_table']);
194  }
195  // todo: don't update column map if value(s) isn't/aren't set.
196  $columnMap->‪setChildSortByFieldName($columnConfiguration['foreign_sortby'] ?? null);
197  $columnMap->‪setChildTableDefaultSortings($columnConfiguration['foreign_default_sortby'] ?? null);
198  $columnMap->‪setParentKeyFieldName($columnConfiguration['foreign_field'] ?? null);
199  $columnMap->‪setParentTableFieldName($columnConfiguration['foreign_table_field'] ?? null);
200  if (isset($columnConfiguration['foreign_match_fields']) && is_array($columnConfiguration['foreign_match_fields'])) {
201  $columnMap->‪setRelationTableMatchFields($columnConfiguration['foreign_match_fields']);
202  }
203  return $columnMap;
204  }
205 
214  protected function ‪setManyToManyRelation(‪ColumnMap $columnMap, array $columnConfiguration = null): ‪ColumnMap
215  {
216  // todo: this method should only be called with proper arguments which means that the TCA integrity check should
217  // todo: take place outside this method.
218 
219  if (isset($columnConfiguration['MM'])) {
220  $columnMap->‪setTypeOfRelation(Relation::HAS_AND_BELONGS_TO_MANY);
221  // check if foreign_table is set, which usually won't be the case for type "group" fields
222  if (!empty($columnConfiguration['foreign_table'])) {
223  $columnMap->‪setChildTableName($columnConfiguration['foreign_table']);
224  }
225  // todo: don't update column map if value(s) isn't/aren't set.
226  $columnMap->‪setRelationTableName($columnConfiguration['MM']);
227  if (isset($columnConfiguration['MM_match_fields']) && is_array($columnConfiguration['MM_match_fields'])) {
228  $columnMap->‪setRelationTableMatchFields($columnConfiguration['MM_match_fields']);
229  }
230  // todo: don't update column map if value(s) isn't/aren't set.
231  if (!empty($columnConfiguration['MM_opposite_field'])) {
232  $columnMap->‪setParentKeyFieldName('uid_foreign');
233  $columnMap->‪setChildKeyFieldName('uid_local');
234  $columnMap->‪setChildSortByFieldName('sorting_foreign');
235  } else {
236  $columnMap->‪setParentKeyFieldName('uid_local');
237  $columnMap->‪setChildKeyFieldName('uid_foreign');
238  $columnMap->‪setChildSortByFieldName('sorting');
239  }
240  } else {
241  // todo: this else part is actually superfluous because \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory::setRelations
242  // todo: only calls this method if $columnConfiguration['MM'] is set.
243 
244  throw new ‪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);
245  }
246  return $columnMap;
247  }
248 }
‪TYPO3\CMS\Extbase\Reflection\ClassSchema\Exception\NoSuchPropertyException
Definition: NoSuchPropertyException.php:24
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap\setTypeOfRelation
‪setTypeOfRelation(ColumnMap\Relation $typeOfRelation)
Definition: ColumnMap.php:122
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMapFactory
Definition: ColumnMapFactory.php:33
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMapFactory\setDateTimeStorageFormat
‪setDateTimeStorageFormat(ColumnMap $columnMap, array $columnConfiguration=null)
Definition: ColumnMapFactory.php:135
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap\setParentKeyFieldName
‪setParentKeyFieldName(?string $parentKeyFieldName)
Definition: ColumnMap.php:187
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMapFactory\setRelations
‪setRelations(ColumnMap $columnMap, ?array $columnConfiguration, ?string $type, ?string $elementType)
Definition: ColumnMapFactory.php:87
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap
Definition: ColumnMap.php:27
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap\setChildTableDefaultSortings
‪setChildTableDefaultSortings(?string $childTableDefaultSortings)
Definition: ColumnMap.php:147
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap\setDateTimeStorageFormat
‪setDateTimeStorageFormat(?string $dateTimeStorageFormat)
Definition: ColumnMap.php:217
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap\setChildTableName
‪setChildTableName(?string $childTableName)
Definition: ColumnMap.php:137
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMapFactory\__construct
‪__construct(private readonly ReflectionService $reflectionService)
Definition: ColumnMapFactory.php:34
‪TYPO3\CMS\Extbase\Reflection\ClassSchema\Exception\NoPropertyTypesException
Definition: NoPropertyTypesException.php:24
‪TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnsupportedRelationException
Definition: UnsupportedRelationException.php:25
‪TYPO3\CMS\Extbase\Reflection\ReflectionService
Definition: ReflectionService.php:28
‪TYPO3\CMS\Core\DataHandling\TableColumnType
‪TableColumnType
Definition: TableColumnType.php:24
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMapFactory\setOneToOneRelation
‪setOneToOneRelation(ColumnMap $columnMap, array $columnConfiguration=null)
Definition: ColumnMapFactory.php:156
‪TYPO3\CMS\Core\Database\Query\QueryHelper
Definition: QueryHelper.php:32
‪TYPO3\CMS\Core\Database\Query\QueryHelper\getDateTimeTypes
‪static array getDateTimeTypes()
Definition: QueryHelper.php:211
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap\setType
‪setType(TableColumnType $type)
Definition: ColumnMap.php:227
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap\getType
‪getType()
Definition: ColumnMap.php:232
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap\setChildKeyFieldName
‪setChildKeyFieldName(string $childKeyFieldName)
Definition: ColumnMap.php:207
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMapFactory\setManyToManyRelation
‪setManyToManyRelation(ColumnMap $columnMap, array $columnConfiguration=null)
Definition: ColumnMapFactory.php:214
‪TYPO3\CMS\Extbase\Reflection\ClassSchema\Exception\NoPropertyTypesException\create
‪static create(string $className, string $propertyName)
Definition: NoPropertyTypesException.php:25
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMapFactory\setType
‪setType(ColumnMap $columnMap, array $columnConfiguration)
Definition: ColumnMapFactory.php:70
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMapFactory\setOneToManyRelation
‪setOneToManyRelation(ColumnMap $columnMap, array $columnConfiguration=null)
Definition: ColumnMapFactory.php:185
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap\setChildSortByFieldName
‪setChildSortByFieldName(?string $childSortByFieldName)
Definition: ColumnMap.php:157
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap\setParentTableFieldName
‪setParentTableFieldName(?string $parentTableFieldName)
Definition: ColumnMap.php:197
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap\setRelationTableMatchFields
‪setRelationTableMatchFields(?array $relationTableMatchFields)
Definition: ColumnMap.php:177
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap\setRelationTableName
‪setRelationTableName(?string $relationTableName)
Definition: ColumnMap.php:167
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap\Relation
‪Relation
Definition: Relation.php:24
‪TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMapFactory\create
‪create(string $columnName, array $columnDefinition, string $propertyName, string $className)
Definition: ColumnMapFactory.php:38