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