Raised DBAL version from 1.1.5 to 1.1.6
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Persistence / Mapper / DataMapFactory.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 *
17 * This script is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * This copyright notice MUST APPEAR in all copies of the script!
23 ***************************************************************/
24
25 /**
26 * A factory for a data map to map a single table configured in $TCA on a domain object.
27 *
28 * @package Extbase
29 * @subpackage Persistence\Mapper
30 * @version $ID:$
31 */
32 class Tx_Extbase_Persistence_Mapper_DataMapFactory {
33
34 /**
35 * @var Tx_Extbase_Reflection_Service
36 */
37 protected $reflectionService;
38
39 /**
40 * Injects the reflection service
41 *
42 * @param Tx_Extbase_Reflection_Service $reflectionService
43 * @return void
44 */
45 public function injectReflectionService(Tx_Extbase_Reflection_Service $reflectionService) {
46 $this->reflectionService = $reflectionService;
47 }
48
49 /**
50 * Builds a data map by adding column maps for all the configured columns in the $TCA.
51 * It also resolves the type of values the column is holding and the typo of relation the column
52 * represents.
53 *
54 * @param string $className The class name you want to fetch the Data Map for
55 * @return Tx_Extbase_Persistence_Mapper_DataMap The data map
56 */
57 public function buildDataMap($className) {
58 $recordType = NULL;
59 $subclasses = array();
60 $tableName = strtolower($className);
61 $columnMapping = array();
62
63 $extbaseFrameworkConfiguration = Tx_Extbase_Dispatcher::getExtbaseFrameworkConfiguration();
64 $classSettings = $extbaseFrameworkConfiguration['persistence']['classes'][$className];
65 if ($classSettings !== NULL) {
66 if (isset($classSettings['subclasses']) && is_array($classSettings['subclasses'])) {
67 $subclasses = $classSettings['subclasses'];
68 }
69 if (isset($classSettings['mapping']['recordType']) && strlen($classSettings['mapping']['recordType']) > 0) {
70 $recordType = $classSettings['mapping']['recordType'];
71 }
72 if (isset($classSettings['mapping']['tableName']) && strlen($classSettings['mapping']['tableName']) > 0) {
73 $tableName = $classSettings['mapping']['tableName'];
74 }
75 $classHierachy = array($className) + class_parents($className);
76 foreach ($classHierachy as $currentClassName) {
77 if (in_array($currentClassName, array('Tx_Extbase_DomainObject_AbstractEntity', 'Tx_Extbase_DomainObject_AbstractValueObject'))) {
78 break;
79 }
80 $currentTableName = strtolower($currentClassName);
81 $currentClassSettings = $extbaseFrameworkConfiguration['persistence']['classes'][$currentClassName];
82 if ($currentClassSettings !== NULL) {
83 if (isset($currentClassSettings['mapping']['columns']) && is_array($currentClassSettings['mapping']['columns'])) {
84 $columnMapping = t3lib_div::array_merge_recursive_overrule($columnMapping, $currentClassSettings['mapping']['columns'], 0, FALSE); // FALSE means: do not include empty values form 2nd array
85 }
86 }
87 }
88 }
89
90 $dataMap = t3lib_div::makeInstance('Tx_Extbase_Persistence_Mapper_DataMap', $className, $tableName, $recordType, $subclasses);
91 $dataMap = $this->addMetaDataColumnNames($dataMap, $tableName);
92
93 // $classPropertyNames = $this->reflectionService->getClassPropertyNames($className);
94 $tcaColumnsDefinition = $this->getColumnsDefinition($tableName);
95 $tcaColumnsDefinition = t3lib_div::array_merge_recursive_overrule($tcaColumnsDefinition, $columnMapping); // TODO Is this is too powerful?
96 foreach ($tcaColumnsDefinition as $columnName => $columnDefinition) {
97 if (isset($columnDefinition['mapOnProperty'])) {
98 $propertyName = $columnDefinition['mapOnProperty'];
99 } else {
100 $propertyName = Tx_Extbase_Utility_Extension::convertUnderscoredToLowerCamelCase($columnName);
101 }
102 // if (in_array($propertyName, $classPropertyNames)) { // TODO Enable check for property existance
103 $columnMap = new Tx_Extbase_Persistence_Mapper_ColumnMap($columnName, $propertyName);
104 $columnMap = $this->setRelations($columnMap, $columnDefinition['config']);
105 $dataMap->addColumnMap($columnMap);
106 // }
107 }
108 // debug($dataMap);
109 return $dataMap;
110 }
111
112 /**
113 * Returns the TCA ctrl section of the specified table; or NULL if not set
114 *
115 * @param string $tableName An optional table name to fetch the columns definition from
116 * @return array The TCA columns definition
117 */
118 protected function getControlSection($tableName) {
119 $this->includeTca($tableName);
120 return is_array($GLOBALS['TCA'][$tableName]['ctrl']) ? $GLOBALS['TCA'][$tableName]['ctrl'] : NULL;
121 }
122
123 /**
124 * Returns the TCA columns array of the specified table
125 *
126 * @param string $tableName An optional table name to fetch the columns definition from
127 * @return array The TCA columns definition
128 */
129 protected function getColumnsDefinition($tableName) {
130 $this->includeTca($tableName);
131 return is_array($GLOBALS['TCA'][$tableName]['columns']) ? $GLOBALS['TCA'][$tableName]['columns'] : array();
132 }
133
134 /**
135 * Includes the TCA for the given table
136 *
137 * @param string $tableName An optional table name to fetch the columns definition from
138 * @return void
139 */
140 protected function includeTca($tableName) {
141 if (TYPO3_MODE === 'FE') {
142 $GLOBALS['TSFE']->includeTCA();
143 }
144 t3lib_div::loadTCA($tableName);
145 }
146
147 protected function addMetaDataColumnNames(Tx_Extbase_Persistence_Mapper_DataMap $dataMap, $tableName) {
148 $controlSection = $GLOBALS['TCA'][$tableName]['ctrl'];
149 $dataMap->setPageIdColumnName('pid');
150 if (isset($controlSection['tstamp'])) $dataMap->setModificationDateColumnName($controlSection['tstamp']);
151 if (isset($controlSection['crdate'])) $dataMap->setCreationDateColumnName($controlSection['crdate']);
152 if (isset($controlSection['cruser_id'])) $dataMap->setCreatorColumnName($controlSection['cruser_id']);
153 if (isset($controlSection['delete'])) $dataMap->setDeletedFlagColumnName($controlSection['delete']);
154 if (isset($controlSection['languageField'])) $dataMap->setLanguageIdColumnName($controlSection['languageField']);
155 if (isset($controlSection['transOrigPointerField'])) $dataMap->setTranslationOriginColumnName($controlSection['transOrigPointerField']);
156 if (isset($controlSection['type'])) $dataMap->setRecordTypeColumnName($controlSection['type']);
157 if (isset($controlSection['enablecolumns']['disabled'])) $dataMap->setDisabledFlagColumnName($controlSection['enablecolumns']['disabled']);
158 if (isset($controlSection['enablecolumns']['starttime'])) $dataMap->setStartTimeColumnName($controlSection['enablecolumns']['starttime']);
159 if (isset($controlSection['enablecolumns']['endtime'])) $dataMap->setEndTimeColumnName($controlSection['enablecolumns']['endtime']);
160 if (isset($controlSection['enablecolumns']['fe_group'])) $dataMap->setFrontEndUserGroupColumnName($controlSection['enablecolumns']['fe_group']);
161 return $dataMap;
162 }
163
164 /**
165 * This method tries to determine the type of type of relation to other tables and sets it based on
166 * the $TCA column configuration
167 *
168 * @param Tx_Extbase_Persistence_Mapper_ColumnMap $columnMap The column map
169 * @param string $columnConfiguration The column configuration from $TCA
170 * @return void
171 */
172 protected function setRelations(Tx_Extbase_Persistence_Mapper_ColumnMap $columnMap, $columnConfiguration) {
173 if (isset($columnConfiguration) && $columnConfiguration['type'] !== 'passthrough') {
174 if (isset($columnConfiguration['foreign_table'])) {
175 if (isset($columnConfiguration['MM']) || isset($columnConfiguration['foreign_selector'])) {
176 $columnMap = $this->setManyToManyRelation($columnMap, $columnConfiguration);
177 } else {
178 if (!isset($columnConfiguration['maxitems']) || $columnConfiguration['maxitems'] == 1) {
179 $columnMap = $this->setOneToOneRelation($columnMap, $columnConfiguration);
180 } else {
181 $columnMap = $this->setOneToManyRelation($columnMap, $columnConfiguration);
182 }
183 }
184 } else {
185 $columnMap->setTypeOfRelation(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_NONE);
186 }
187 }
188 return $columnMap;
189 }
190
191 /**
192 * This method sets the configuration for a 1:1 relation based on
193 * the $TCA column configuration
194 *
195 * @param string $columnMap The column map
196 * @param string $columnConfiguration The column configuration from $TCA
197 * @return void
198 */
199 protected function setOneToOneRelation(Tx_Extbase_Persistence_Mapper_ColumnMap $columnMap, $columnConfiguration) {
200 $columnMap->setTypeOfRelation(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_ONE);
201 $columnMap->setChildTableName($columnConfiguration['foreign_table']);
202 $columnMap->setChildTableWhereStatement($columnConfiguration['foreign_table_where']);
203 $columnMap->setChildSortbyFieldName($columnConfiguration['foreign_sortby']);
204 $columnMap->setParentKeyFieldName($columnConfiguration['foreign_field']);
205 $columnMap->setParentTableFieldName($columnConfiguration['foreign_table_field']);
206 return $columnMap;
207 }
208
209 /**
210 * This method sets the configuration for a 1:n relation based on
211 * the $TCA column configuration
212 *
213 * @param string $columnMap The column map
214 * @param string $columnConfiguration The column configuration from $TCA
215 * @return void
216 */
217 protected function setOneToManyRelation(Tx_Extbase_Persistence_Mapper_ColumnMap $columnMap, $columnConfiguration) {
218 $columnMap->setTypeOfRelation(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_MANY);
219 $columnMap->setChildTableName($columnConfiguration['foreign_table']);
220 $columnMap->setChildTableWhereStatement($columnConfiguration['foreign_table_where']);
221 $columnMap->setChildSortbyFieldName($columnConfiguration['foreign_sortby']);
222 $columnMap->setParentKeyFieldName($columnConfiguration['foreign_field']);
223 $columnMap->setParentTableFieldName($columnConfiguration['foreign_table_field']);
224 return $columnMap;
225 }
226
227 /**
228 * This method sets the configuration for a m:n relation based on
229 * the $TCA column configuration
230 *
231 * @param string $columnMap The column map
232 * @param string $columnConfiguration The column configuration from $TCA
233 * @return void
234 */
235 protected function setManyToManyRelation(Tx_Extbase_Persistence_Mapper_ColumnMap $columnMap, $columnConfiguration) {
236 $columnMap->setTypeOfRelation(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY);
237 if (isset($columnConfiguration['MM'])) {
238 $columnMap->setChildTableName($columnConfiguration['foreign_table']);
239 $columnMap->setChildTableWhereStatement($columnConfiguration['foreign_table_where']);
240 $columnMap->setRelationTableName($columnConfiguration['MM']);
241 if (is_array($columnConfiguration['MM_match_fields'])) {
242 $columnMap->setRelationTableMatchFields($columnConfiguration['MM_match_fields']);
243 }
244 if (is_array($columnConfiguration['MM_insert_fields'])) {
245 $columnMap->setRelationTableInsertFields($columnConfiguration['MM_insert_fields']);
246 }
247 $columnMap->setRelationTableWhereStatement($columnConfiguration['MM_table_where']);
248 if (!empty($columnConfiguration['MM_opposite_field'])) {
249 $columnMap->setParentKeyFieldName('uid_foreign');
250 $columnMap->setChildKeyFieldName('uid_local');
251 $columnMap->setChildSortByFieldName('sorting_foreign');
252 } else {
253 $columnMap->setParentKeyFieldName('uid_local');
254 $columnMap->setChildKeyFieldName('uid_foreign');
255 $columnMap->setChildSortByFieldName('sorting');
256 }
257 } elseif (isset($columnConfiguration['foreign_selector'])) {
258 $columns = $this->getColumnsDefinition($columnConfiguration['foreign_table']);
259 $childKeyFieldName = $columnConfiguration['foreign_selector'];
260 $columnMap->setChildTableName($columns[$childKeyFieldName]['config']['foreign_table']);
261 $columnMap->setRelationTableName($columnConfiguration['foreign_table']);
262 $columnMap->setParentKeyFieldName($columnConfiguration['foreign_field']);
263 $columnMap->setChildKeyFieldName($childKeyFieldName);
264 $columnMap->setChildSortByFieldName($columnConfiguration['foreign_sortby']);
265 } else {
266 throw new Tx_Extbase_Persistence_Exception_UnsupportedRelation('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);
267 }
268 if ($this->getControlSection($columnMap->getRelationTableName()) !== NULL) {
269 $columnMap->setRelationTablePageIdColumnName('pid');
270 }
271 return $columnMap;
272 }
273
274 }