c8bcc531dc316b1017fac66a6f05456be47cf355
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Persistence / Generic / Mapper / DataMapper.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Persistence\Generic\Mapper;
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
17 use TYPO3\CMS\Extbase\Utility\TypeHandlingUtility;
18
19 /**
20 * A mapper to map database tables configured in $TCA on domain objects.
21 */
22 class DataMapper implements \TYPO3\CMS\Core\SingletonInterface {
23
24 /**
25 * @var \TYPO3\CMS\Extbase\Persistence\Generic\IdentityMap
26 * @inject
27 */
28 protected $identityMap;
29
30 /**
31 * @var \TYPO3\CMS\Extbase\Reflection\ReflectionService
32 * @inject
33 */
34 protected $reflectionService;
35
36 /**
37 * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory
38 * @inject
39 */
40 protected $qomFactory;
41
42 /**
43 * @var \TYPO3\CMS\Extbase\Persistence\Generic\Session
44 * @inject
45 */
46 protected $persistenceSession;
47
48 /**
49 * A reference to the page select object providing methods to perform language and work space overlays
50 *
51 * @var \TYPO3\CMS\Frontend\Page\PageRepository
52 */
53 protected $pageSelectObject;
54
55 /**
56 * Cached data maps
57 *
58 * @var array
59 */
60 protected $dataMaps = array();
61
62 /**
63 * @var \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory
64 * @inject
65 */
66 protected $dataMapFactory;
67
68 /**
69 * @var \TYPO3\CMS\Extbase\Persistence\Generic\QueryFactoryInterface
70 * @inject
71 */
72 protected $queryFactory;
73
74 /**
75 * The TYPO3 reference index object
76 *
77 * @var \TYPO3\CMS\Core\Database\ReferenceIndex
78 */
79 protected $referenceIndex;
80
81 /**
82 * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
83 * @inject
84 */
85 protected $objectManager;
86
87 /**
88 * Maps the given rows on objects
89 *
90 * @param string $className The name of the class
91 * @param array $rows An array of arrays with field_name => value pairs
92 * @return array An array of objects of the given class
93 */
94 public function map($className, array $rows) {
95 $objects = array();
96 foreach ($rows as $row) {
97 $objects[] = $this->mapSingleRow($this->getTargetType($className, $row), $row);
98 }
99 return $objects;
100 }
101
102 /**
103 * Returns the target type for the given row.
104 *
105 * @param string $className The name of the class
106 * @param array $row A single array with field_name => value pairs
107 * @return string The target type (a class name)
108 */
109 public function getTargetType($className, array $row) {
110 $dataMap = $this->getDataMap($className);
111 $targetType = $className;
112 if ($dataMap->getRecordTypeColumnName() !== NULL) {
113 foreach ($dataMap->getSubclasses() as $subclassName) {
114 $recordSubtype = $this->getDataMap($subclassName)->getRecordType();
115 if ($row[$dataMap->getRecordTypeColumnName()] === $recordSubtype) {
116 $targetType = $subclassName;
117 break;
118 }
119 }
120 }
121 return $targetType;
122 }
123
124 /**
125 * Maps a single row on an object of the given class
126 *
127 * @param string $className The name of the target class
128 * @param array $row A single array with field_name => value pairs
129 * @return object An object of the given class
130 */
131 protected function mapSingleRow($className, array $row) {
132 if ($this->identityMap->hasIdentifier($row['uid'], $className)) {
133 $object = $this->identityMap->getObjectByIdentifier($row['uid'], $className);
134 } else {
135 $object = $this->createEmptyObject($className);
136 $this->identityMap->registerObject($object, $row['uid']);
137 $this->thawProperties($object, $row);
138 $object->_memorizeCleanState();
139 $this->persistenceSession->registerReconstitutedEntity($object);
140 }
141 return $object;
142 }
143
144 /**
145 * Creates a skeleton of the specified object
146 *
147 * @param string $className Name of the class to create a skeleton for
148 * @throws \TYPO3\CMS\Extbase\Object\Exception\CannotReconstituteObjectException
149 * @return object The object skeleton
150 */
151 protected function createEmptyObject($className) {
152 // Note: The class_implements() function also invokes autoload to assure that the interfaces
153 // and the class are loaded. Would end up with __PHP_Incomplete_Class without it.
154 if (!in_array('TYPO3\\CMS\\Extbase\\DomainObject\\DomainObjectInterface', class_implements($className))) {
155 throw new \TYPO3\CMS\Extbase\Object\Exception\CannotReconstituteObjectException('Cannot create empty instance of the class "' . $className . '" because it does not implement the TYPO3\\CMS\\Extbase\\DomainObject\\DomainObjectInterface.', 1234386924);
156 }
157 $object = $this->objectManager->getEmptyObject($className);
158 return $object;
159 }
160
161 /**
162 * Sets the given properties on the object.
163 *
164 * @param \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object The object to set properties on
165 * @param array $row
166 * @return void
167 */
168 protected function thawProperties(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, array $row) {
169 $className = get_class($object);
170 $classSchema = $this->reflectionService->getClassSchema($className);
171 $dataMap = $this->getDataMap($className);
172 $object->_setProperty('uid', (int)$row['uid']);
173 $object->_setProperty('pid', (int)$row['pid']);
174 $object->_setProperty('_localizedUid', (int)$row['uid']);
175 if ($dataMap->getLanguageIdColumnName() !== NULL) {
176 $object->_setProperty('_languageUid', (int)$row[$dataMap->getLanguageIdColumnName()]);
177 if (isset($row['_LOCALIZED_UID'])) {
178 $object->_setProperty('_localizedUid', (int)$row['_LOCALIZED_UID']);
179 }
180 }
181 $properties = $object->_getProperties();
182 foreach ($properties as $propertyName => $propertyValue) {
183 if (!$dataMap->isPersistableProperty($propertyName)) {
184 continue;
185 }
186 $columnMap = $dataMap->getColumnMap($propertyName);
187 $columnName = $columnMap->getColumnName();
188 $propertyData = $classSchema->getProperty($propertyName);
189 $propertyValue = NULL;
190 if ($row[$columnName] !== NULL) {
191 switch ($propertyData['type']) {
192 case 'integer':
193 $propertyValue = (int)$row[$columnName];
194 break;
195 case 'float':
196 $propertyValue = (double)$row[$columnName];
197 break;
198 case 'boolean':
199 $propertyValue = (bool)$row[$columnName];
200 break;
201 case 'string':
202 $propertyValue = (string)$row[$columnName];
203 break;
204 case 'array':
205 // $propertyValue = $this->mapArray($row[$columnName]); // Not supported, yet!
206 break;
207 case 'SplObjectStorage':
208 case 'Tx_Extbase_Persistence_ObjectStorage':
209 case 'TYPO3\\CMS\\Extbase\\Persistence\\ObjectStorage':
210 $propertyValue = $this->mapResultToPropertyValue(
211 $object,
212 $propertyName,
213 $this->fetchRelated($object, $propertyName, $row[$columnName])
214 );
215 break;
216 default:
217 if ($propertyData['type'] === 'DateTime' || in_array('DateTime', class_parents($propertyData['type']))) {
218 $propertyValue = $this->mapDateTime($row[$columnName], $columnMap->getDateTimeStorageFormat());
219 } elseif (TypeHandlingUtility::isCoreType($propertyData['type'])) {
220 $propertyValue = $this->mapCoreType($propertyData['type'], $row[$columnName]);
221 } else {
222 $propertyValue = $this->mapObjectToClassProperty(
223 $object,
224 $propertyName,
225 $row[$columnName]
226 );
227 }
228
229 }
230 }
231 if ($propertyValue !== NULL) {
232 $object->_setProperty($propertyName, $propertyValue);
233 }
234 }
235 }
236
237 /**
238 * Map value to a core type
239 *
240 * @param string $type
241 * @param mixed $value
242 * @return \TYPO3\CMS\Core\Type\TypeInterface
243 */
244 protected function mapCoreType($type, $value) {
245 return new $type($value);
246 }
247
248 /**
249 * Creates a DateTime from an unix timestamp or date/datetime value.
250 * If the input is empty, NULL is returned.
251 *
252 * @param integer|string $value Unix timestamp or date/datetime value
253 * @param NULL|string $storageFormat Storage format for native date/datetime fields
254 * @return \DateTime
255 */
256 protected function mapDateTime($value, $storageFormat = NULL) {
257 if (empty($value) || $value === '0000-00-00' || $value === '0000-00-00 00:00:00') {
258 // 0 -> NULL !!!
259 return NULL;
260 } elseif ($storageFormat === 'date' || $storageFormat === 'datetime') {
261 // native date/datetime values are stored in UTC
262 $utcTimeZone = new \DateTimeZone('UTC');
263 $utcDateTime = new \DateTime($value, $utcTimeZone);
264 $currentTimeZone = new \DateTimeZone(date_default_timezone_get());
265 return $utcDateTime->setTimezone($currentTimeZone);
266 } else {
267 return new \DateTime(date('c', $value));
268 }
269 }
270
271 /**
272 * Fetches a collection of objects related to a property of a parent object
273 *
274 * @param \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject The object instance this proxy is part of
275 * @param string $propertyName The name of the proxied property in it's parent
276 * @param mixed $fieldValue The raw field value.
277 * @param boolean $enableLazyLoading A flag indication if the related objects should be lazy loaded
278 * @return \TYPO3\CMS\Extbase\Persistence\Generic\LazyObjectStorage|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface The result
279 */
280 public function fetchRelated(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $propertyName, $fieldValue = '', $enableLazyLoading = TRUE) {
281 $propertyMetaData = $this->reflectionService->getClassSchema(get_class($parentObject))->getProperty($propertyName);
282 if ($enableLazyLoading === TRUE && $propertyMetaData['lazy']) {
283 if (in_array($propertyMetaData['type'], array('TYPO3\\CMS\\Extbase\\Persistence\\ObjectStorage', 'Tx_Extbase_Persistence_ObjectStorage'), TRUE)) {
284 $result = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\LazyObjectStorage', $parentObject, $propertyName, $fieldValue);
285 } else {
286 if (empty($fieldValue)) {
287 $result = NULL;
288 } else {
289 $result = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\LazyLoadingProxy', $parentObject, $propertyName, $fieldValue);
290 }
291 }
292 } else {
293 $result = $this->fetchRelatedEager($parentObject, $propertyName, $fieldValue);
294 }
295 return $result;
296 }
297
298 /**
299 * Fetches the related objects from the storage backend.
300 *
301 * @param \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject The object instance this proxy is part of
302 * @param string $propertyName The name of the proxied property in it's parent
303 * @param mixed $fieldValue The raw field value.
304 * @return mixed
305 */
306 protected function fetchRelatedEager(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $propertyName, $fieldValue = '') {
307 return $fieldValue === '' ? $this->getEmptyRelationValue($parentObject, $propertyName) : $this->getNonEmptyRelationValue($parentObject, $propertyName, $fieldValue);
308 }
309
310 /**
311 * @param \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject
312 * @param string $propertyName
313 * @return array|NULL
314 */
315 protected function getEmptyRelationValue(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $propertyName) {
316 $columnMap = $this->getDataMap(get_class($parentObject))->getColumnMap($propertyName);
317 $relatesToOne = $columnMap->getTypeOfRelation() == \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_ONE;
318 return $relatesToOne ? NULL : array();
319 }
320
321 /**
322 * @param \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject
323 * @param string $propertyName
324 * @param string $fieldValue
325 * @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface
326 */
327 protected function getNonEmptyRelationValue(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $propertyName, $fieldValue) {
328 $query = $this->getPreparedQuery($parentObject, $propertyName, $fieldValue);
329 return $query->execute();
330 }
331
332 /**
333 * Builds and returns the prepared query, ready to be executed.
334 *
335 * @param \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject
336 * @param string $propertyName
337 * @param string $fieldValue
338 * @return \TYPO3\CMS\Extbase\Persistence\QueryInterface
339 */
340 protected function getPreparedQuery(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $propertyName, $fieldValue = '') {
341 $columnMap = $this->getDataMap(get_class($parentObject))->getColumnMap($propertyName);
342 $type = $this->getType(get_class($parentObject), $propertyName);
343 $query = $this->queryFactory->create($type);
344 $query->getQuerySettings()->setRespectStoragePage(FALSE);
345 $query->getQuerySettings()->setRespectSysLanguage(FALSE);
346 if ($columnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_MANY) {
347 if ($columnMap->getChildSortByFieldName() !== NULL) {
348 $query->setOrderings(array($columnMap->getChildSortByFieldName() => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING));
349 }
350 } elseif ($columnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
351 $query->setSource($this->getSource($parentObject, $propertyName));
352 if ($columnMap->getChildSortByFieldName() !== NULL) {
353 $query->setOrderings(array($columnMap->getChildSortByFieldName() => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING));
354 }
355 }
356 $query->matching($this->getConstraint($query, $parentObject, $propertyName, $fieldValue, $columnMap->getRelationTableMatchFields()));
357 return $query;
358 }
359
360 /**
361 * Builds and returns the constraint for multi value properties.
362 *
363 * @param \TYPO3\CMS\Extbase\Persistence\QueryInterface $query
364 * @param \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject
365 * @param string $propertyName
366 * @param string $fieldValue
367 * @param array $relationTableMatchFields
368 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint
369 */
370 protected function getConstraint(\TYPO3\CMS\Extbase\Persistence\QueryInterface $query, \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $propertyName, $fieldValue = '', $relationTableMatchFields = array()) {
371 $columnMap = $this->getDataMap(get_class($parentObject))->getColumnMap($propertyName);
372 if ($columnMap->getParentKeyFieldName() !== NULL) {
373 $constraint = $query->equals($columnMap->getParentKeyFieldName(), $parentObject);
374 if ($columnMap->getParentTableFieldName() !== NULL) {
375 $constraint = $query->logicalAnd($constraint, $query->equals($columnMap->getParentTableFieldName(), $this->getDataMap(get_class($parentObject))->getTableName()));
376 }
377 } else {
378 $constraint = $query->in('uid', \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $fieldValue));
379 }
380 if (count($relationTableMatchFields) > 0) {
381 foreach ($relationTableMatchFields as $relationTableMatchFieldName => $relationTableMatchFieldValue) {
382 $constraint = $query->logicalAnd($constraint, $query->equals($relationTableMatchFieldName, $relationTableMatchFieldValue));
383 }
384 }
385 return $constraint;
386 }
387
388 /**
389 * Builds and returns the source to build a join for a m:n relation.
390 *
391 * @param \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject
392 * @param string $propertyName
393 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source
394 */
395 protected function getSource(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $propertyName) {
396 $columnMap = $this->getDataMap(get_class($parentObject))->getColumnMap($propertyName);
397 $left = $this->qomFactory->selector(NULL, $columnMap->getRelationTableName());
398 $childClassName = $this->getType(get_class($parentObject), $propertyName);
399 $right = $this->qomFactory->selector($childClassName, $columnMap->getChildTableName());
400 $joinCondition = $this->qomFactory->equiJoinCondition($columnMap->getRelationTableName(), $columnMap->getChildKeyFieldName(), $columnMap->getChildTableName(), 'uid');
401 $source = $this->qomFactory->join($left, $right, \TYPO3\CMS\Extbase\Persistence\Generic\Query::JCR_JOIN_TYPE_INNER, $joinCondition);
402 return $source;
403 }
404
405 /**
406 * Returns the mapped classProperty from the identiyMap or
407 * mapResultToPropertyValue()
408 *
409 * If the field value is empty and the column map has no parent key field name,
410 * the relation will be empty. If the identityMap has a registered object of
411 * the correct type and identity (fieldValue), this function returns that object.
412 * Otherwise, it proceeds with mapResultToPropertyValue().
413 *
414 * @param \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject
415 * @param string $propertyName
416 * @param mixed $fieldValue the raw field value
417 * @return mixed
418 * @see mapResultToPropertyValue()
419 */
420 protected function mapObjectToClassProperty(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $propertyName, $fieldValue) {
421 if ($this->propertyMapsByForeignKey($parentObject, $propertyName)) {
422 $result = $this->fetchRelated($parentObject, $propertyName, $fieldValue);
423 $propertyValue = $this->mapResultToPropertyValue($parentObject, $propertyName, $result);
424 } else {
425 if ($fieldValue === '') {
426 $propertyValue = $this->getEmptyRelationValue($parentObject, $propertyName);
427 } else {
428 $propertyMetaData = $this->reflectionService->getClassSchema(get_class($parentObject))->getProperty($propertyName);
429 if ($this->persistenceSession->hasIdentifier($fieldValue, $propertyMetaData['type'])) {
430 $propertyValue = $this->persistenceSession->getObjectByIdentifier($fieldValue, $propertyMetaData['type']);
431 } else {
432 $result = $this->fetchRelated($parentObject, $propertyName, $fieldValue);
433 $propertyValue = $this->mapResultToPropertyValue($parentObject, $propertyName, $result);
434 }
435 }
436 }
437
438 return $propertyValue;
439 }
440
441 /**
442 * Checks if the relation is based on a foreign key.
443 *
444 * @param \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject
445 * @param string $propertyName
446 * @return boolean TRUE if the property is mapped
447 */
448 protected function propertyMapsByForeignKey(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $propertyName) {
449 $columnMap = $this->getDataMap(get_class($parentObject))->getColumnMap($propertyName);
450 return ($columnMap->getParentKeyFieldName() !== NULL);
451 }
452
453 /**
454 * Returns the given result as property value of the specified property type.
455 *
456 * @param \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject
457 * @param string $propertyName
458 * @param mixed $result The result
459 * @return mixed
460 */
461 public function mapResultToPropertyValue(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $propertyName, $result) {
462 $propertyValue = NULL;
463 if ($result instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LoadingStrategyInterface) {
464 $propertyValue = $result;
465 } else {
466 $propertyMetaData = $this->reflectionService->getClassSchema(get_class($parentObject))->getProperty($propertyName);
467 if (in_array($propertyMetaData['type'], array('array', 'ArrayObject', 'SplObjectStorage', 'Tx_Extbase_Persistence_ObjectStorage', 'TYPO3\\CMS\\Extbase\\Persistence\\ObjectStorage'), TRUE)) {
468 $objects = array();
469 foreach ($result as $value) {
470 $objects[] = $value;
471 }
472 if ($propertyMetaData['type'] === 'ArrayObject') {
473 $propertyValue = new \ArrayObject($objects);
474 } elseif (in_array($propertyMetaData['type'], array('TYPO3\\CMS\\Extbase\\Persistence\\ObjectStorage', 'Tx_Extbase_Persistence_ObjectStorage'), TRUE)) {
475 $propertyValue = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
476 foreach ($objects as $object) {
477 $propertyValue->attach($object);
478 }
479 $propertyValue->_memorizeCleanState();
480 } else {
481 $propertyValue = $objects;
482 }
483 } elseif (strpbrk($propertyMetaData['type'], '_\\') !== FALSE) {
484 if (is_object($result) && $result instanceof \TYPO3\CMS\Extbase\Persistence\QueryResultInterface) {
485 $propertyValue = $result->getFirst();
486 } else {
487 $propertyValue = $result;
488 }
489 }
490 }
491 return $propertyValue;
492 }
493
494 /**
495 * Counts the number of related objects assigned to a property of a parent object
496 *
497 * @param \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject The object instance this proxy is part of
498 * @param string $propertyName The name of the proxied property in it's parent
499 * @param mixed $fieldValue The raw field value.
500 * @return integer
501 */
502 public function countRelated(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $parentObject, $propertyName, $fieldValue = '') {
503 $query = $this->getPreparedQuery($parentObject, $propertyName, $fieldValue);
504 return $query->execute()->count();
505 }
506
507 /**
508 * Delegates the call to the Data Map.
509 * Returns TRUE if the property is persistable (configured in $TCA)
510 *
511 * @param string $className The property name
512 * @param string $propertyName The property name
513 * @return boolean TRUE if the property is persistable (configured in $TCA)
514 */
515 public function isPersistableProperty($className, $propertyName) {
516 $dataMap = $this->getDataMap($className);
517 return $dataMap->isPersistableProperty($propertyName);
518 }
519
520 /**
521 * Returns a data map for a given class name
522 *
523 * @param string $className The class name you want to fetch the Data Map for
524 * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception
525 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMap The data map
526 */
527 public function getDataMap($className) {
528 if (!is_string($className) || strlen($className) === 0) {
529 throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception('No class name was given to retrieve the Data Map for.', 1251315965);
530 }
531 if (!isset($this->dataMaps[$className])) {
532 $this->dataMaps[$className] = $this->dataMapFactory->buildDataMap($className);
533 }
534 return $this->dataMaps[$className];
535 }
536
537 /**
538 * Returns the selector (table) name for a given class name.
539 *
540 * @param string $className
541 * @return string The selector name
542 */
543 public function convertClassNameToTableName($className = NULL) {
544 if ($className !== NULL) {
545 $tableName = $this->getDataMap($className)->getTableName();
546 } else {
547 $tableName = strtolower($className);
548 }
549 return $tableName;
550 }
551
552 /**
553 * Returns the column name for a given property name of the specified class.
554 *
555 * @param string $propertyName
556 * @param string $className
557 * @return string The column name
558 */
559 public function convertPropertyNameToColumnName($propertyName, $className = NULL) {
560 if (!empty($className)) {
561 $dataMap = $this->getDataMap($className);
562 if ($dataMap !== NULL) {
563 $columnMap = $dataMap->getColumnMap($propertyName);
564 if ($columnMap !== NULL) {
565 return $columnMap->getColumnName();
566 }
567 }
568 }
569 return \TYPO3\CMS\Core\Utility\GeneralUtility::camelCaseToLowerCaseUnderscored($propertyName);
570 }
571
572 /**
573 * Returns the type of a child object.
574 *
575 * @param string $parentClassName The class name of the object this proxy is part of
576 * @param string $propertyName The name of the proxied property in it's parent
577 * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException
578 * @return string The class name of the child object
579 */
580 public function getType($parentClassName, $propertyName) {
581 $propertyMetaData = $this->reflectionService->getClassSchema($parentClassName)->getProperty($propertyName);
582 if (!empty($propertyMetaData['elementType'])) {
583 $type = $propertyMetaData['elementType'];
584 } elseif (!empty($propertyMetaData['type'])) {
585 $type = $propertyMetaData['type'];
586 } else {
587 throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException('Could not determine the child object type.', 1251315967);
588 }
589 return $type;
590 }
591 }