2 namespace TYPO3\CMS\Extbase\Persistence\Generic\Mapper
;
5 * This file is part of the TYPO3 CMS project.
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.
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
14 * The TYPO3 project - inspiring people to share!
17 use TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface
;
18 use TYPO3\CMS\Extbase\
Object\Exception\CannotReconstituteObjectException
;
19 use TYPO3\CMS\Extbase\Persistence
;
20 use TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException
;
21 use TYPO3\CMS\Extbase\Utility\TypeHandlingUtility
;
24 * A mapper to map database tables configured in $TCA on domain objects.
26 class DataMapper
implements \TYPO3\CMS\Core\SingletonInterface
29 * @var \TYPO3\CMS\Extbase\Reflection\ReflectionService
31 protected $reflectionService;
34 * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory
36 protected $qomFactory;
39 * @var \TYPO3\CMS\Extbase\Persistence\Generic\Session
41 protected $persistenceSession;
44 * A reference to the page select object providing methods to perform language and work space overlays
46 * @var \TYPO3\CMS\Frontend\Page\PageRepository
48 protected $pageSelectObject;
55 protected $dataMaps = [];
58 * @var \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory
60 protected $dataMapFactory;
63 * @var \TYPO3\CMS\Extbase\Persistence\Generic\QueryFactoryInterface
65 protected $queryFactory;
68 * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
70 protected $objectManager;
73 * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
75 protected $signalSlotDispatcher;
78 * @param \TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService
80 public function injectReflectionService(\TYPO3\CMS\Extbase\Reflection\ReflectionService
$reflectionService)
82 $this->reflectionService
= $reflectionService;
86 * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory
88 public function injectQomFactory(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory
$qomFactory)
90 $this->qomFactory
= $qomFactory;
94 * @param \TYPO3\CMS\Extbase\Persistence\Generic\Session $persistenceSession
96 public function injectPersistenceSession(\TYPO3\CMS\Extbase\Persistence\Generic\Session
$persistenceSession)
98 $this->persistenceSession
= $persistenceSession;
102 * @param \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory $dataMapFactory
104 public function injectDataMapFactory(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory
$dataMapFactory)
106 $this->dataMapFactory
= $dataMapFactory;
110 * @param \TYPO3\CMS\Extbase\Persistence\Generic\QueryFactoryInterface $queryFactory
112 public function injectQueryFactory(\TYPO3\CMS\Extbase\Persistence\Generic\QueryFactoryInterface
$queryFactory)
114 $this->queryFactory
= $queryFactory;
118 * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
120 public function injectObjectManager(\TYPO3\CMS\Extbase\
Object\ObjectManagerInterface
$objectManager)
122 $this->objectManager
= $objectManager;
126 * @param \TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher
128 public function injectSignalSlotDispatcher(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher
$signalSlotDispatcher)
130 $this->signalSlotDispatcher
= $signalSlotDispatcher;
134 * Maps the given rows on objects
136 * @param string $className The name of the class
137 * @param array $rows An array of arrays with field_name => value pairs
138 * @return array An array of objects of the given class
140 public function map($className, array $rows)
143 foreach ($rows as $row) {
144 $objects[] = $this->mapSingleRow($this->getTargetType($className, $row), $row);
150 * Returns the target type for the given row.
152 * @param string $className The name of the class
153 * @param array $row A single array with field_name => value pairs
154 * @return string The target type (a class name)
156 public function getTargetType($className, array $row)
158 $dataMap = $this->getDataMap($className);
159 $targetType = $className;
160 if ($dataMap->getRecordTypeColumnName() !== null) {
161 foreach ($dataMap->getSubclasses() as $subclassName) {
162 $recordSubtype = $this->getDataMap($subclassName)->getRecordType();
163 if ((string)$row[$dataMap->getRecordTypeColumnName()] === (string)$recordSubtype) {
164 $targetType = $subclassName;
173 * Maps a single row on an object of the given class
175 * @param string $className The name of the target class
176 * @param array $row A single array with field_name => value pairs
177 * @return object An object of the given class
179 protected function mapSingleRow($className, array $row)
181 if ($this->persistenceSession
->hasIdentifier($row['uid'], $className)) {
182 $object = $this->persistenceSession
->getObjectByIdentifier($row['uid'], $className);
184 $object = $this->createEmptyObject($className);
185 $this->persistenceSession
->registerObject($object, $row['uid']);
186 $this->thawProperties($object, $row);
187 $this->emitAfterMappingSingleRow($object);
188 $object->_memorizeCleanState();
189 $this->persistenceSession
->registerReconstitutedEntity($object);
195 * Emits a signal after mapping a single row.
197 * @param DomainObjectInterface $object The mapped object
199 protected function emitAfterMappingSingleRow(DomainObjectInterface
$object)
201 $this->signalSlotDispatcher
->dispatch(__CLASS__
, 'afterMappingSingleRow', [$object]);
205 * Creates a skeleton of the specified object
207 * @param string $className Name of the class to create a skeleton for
208 * @throws CannotReconstituteObjectException
209 * @return object The object skeleton
211 protected function createEmptyObject($className)
213 // Note: The class_implements() function also invokes autoload to assure that the interfaces
214 // and the class are loaded. Would end up with __PHP_Incomplete_Class without it.
215 if (!in_array(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface
::class, class_implements($className))) {
216 throw new CannotReconstituteObjectException('Cannot create empty instance of the class "' . $className
217 . '" because it does not implement the TYPO3\\CMS\\Extbase\\DomainObject\\DomainObjectInterface.', 1234386924);
219 $object = $this->objectManager
->getEmptyObject($className);
224 * Sets the given properties on the object.
226 * @param DomainObjectInterface $object The object to set properties on
229 protected function thawProperties(DomainObjectInterface
$object, array $row)
231 $className = get_class($object);
232 $classSchema = $this->reflectionService
->getClassSchema($className);
233 $dataMap = $this->getDataMap($className);
234 $object->_setProperty('uid', (int)$row['uid']);
235 $object->_setProperty('pid', (int)$row['pid']);
236 $object->_setProperty('_localizedUid', (int)$row['uid']);
237 $object->_setProperty('_versionedUid', (int)$row['uid']);
238 if ($dataMap->getLanguageIdColumnName() !== null) {
239 $object->_setProperty('_languageUid', (int)$row[$dataMap->getLanguageIdColumnName()]);
240 if (isset($row['_LOCALIZED_UID'])) {
241 $object->_setProperty('_localizedUid', (int)$row['_LOCALIZED_UID']);
244 if (!empty($row['_ORIG_uid']) && !empty($GLOBALS['TCA'][$dataMap->getTableName()]['ctrl']['versioningWS'])) {
245 $object->_setProperty('_versionedUid', (int)$row['_ORIG_uid']);
247 $properties = $object->_getProperties();
248 foreach ($properties as $propertyName => $propertyValue) {
249 if (!$dataMap->isPersistableProperty($propertyName)) {
252 $columnMap = $dataMap->getColumnMap($propertyName);
253 $columnName = $columnMap->getColumnName();
254 $propertyData = $classSchema->getProperty($propertyName);
255 $propertyValue = null;
256 if ($row[$columnName] !== null) {
257 switch ($propertyData['type']) {
259 $propertyValue = (int)$row[$columnName];
262 $propertyValue = (double)$row[$columnName];
265 $propertyValue = (bool)$row[$columnName];
268 $propertyValue = (string)$row[$columnName];
271 // $propertyValue = $this->mapArray($row[$columnName]); // Not supported, yet!
273 case 'SplObjectStorage':
274 case \TYPO3\CMS\Extbase\Persistence\ObjectStorage
::class:
275 $propertyValue = $this->mapResultToPropertyValue(
278 $this->fetchRelated($object, $propertyName, $row[$columnName])
282 if ($propertyData['type'] === 'DateTime' ||
in_array('DateTime', class_parents($propertyData['type']))) {
283 $propertyValue = $this->mapDateTime($row[$columnName], $columnMap->getDateTimeStorageFormat(), $propertyData['type']);
284 } elseif (TypeHandlingUtility
::isCoreType($propertyData['type'])) {
285 $propertyValue = $this->mapCoreType($propertyData['type'], $row[$columnName]);
287 $propertyValue = $this->mapObjectToClassProperty(
296 if ($propertyValue !== null) {
297 $object->_setProperty($propertyName, $propertyValue);
303 * Map value to a core type
305 * @param string $type
306 * @param mixed $value
307 * @return \TYPO3\CMS\Core\Type\TypeInterface
309 protected function mapCoreType($type, $value)
311 return new $type($value);
315 * Creates a DateTime from an unix timestamp or date/datetime value.
316 * If the input is empty, NULL is returned.
318 * @param int|string $value Unix timestamp or date/datetime value
319 * @param NULL|string $storageFormat Storage format for native date/datetime fields
320 * @param NULL|string $targetType The object class name to be created
323 protected function mapDateTime($value, $storageFormat = null, $targetType = 'DateTime')
325 if (empty($value) ||
$value === '0000-00-00' ||
$value === '0000-00-00 00:00:00') {
329 if ($storageFormat === 'date' ||
$storageFormat === 'datetime') {
330 // native date/datetime values are stored in UTC
331 $utcTimeZone = new \
DateTimeZone('UTC');
332 $utcDateTime = \TYPO3\CMS\Core\Utility\GeneralUtility
::makeInstance($targetType, $value, $utcTimeZone);
333 $currentTimeZone = new \
DateTimeZone(date_default_timezone_get());
334 return $utcDateTime->setTimezone($currentTimeZone);
336 // integer timestamps are local server time
337 return \TYPO3\CMS\Core\Utility\GeneralUtility
::makeInstance($targetType, date('c', $value));
341 * Fetches a collection of objects related to a property of a parent object
343 * @param DomainObjectInterface $parentObject The object instance this proxy is part of
344 * @param string $propertyName The name of the proxied property in it's parent
345 * @param mixed $fieldValue The raw field value.
346 * @param bool $enableLazyLoading A flag indication if the related objects should be lazy loaded
347 * @return \TYPO3\CMS\Extbase\Persistence\Generic\LazyObjectStorage|Persistence\QueryResultInterface The result
349 public function fetchRelated(DomainObjectInterface
$parentObject, $propertyName, $fieldValue = '', $enableLazyLoading = true)
351 $propertyMetaData = $this->reflectionService
->getClassSchema(get_class($parentObject))->getProperty($propertyName);
352 if ($enableLazyLoading === true && $propertyMetaData['annotations']['lazy']) {
353 if ($propertyMetaData['type'] === \TYPO3\CMS\Extbase\Persistence\ObjectStorage
::class) {
354 $result = $this->objectManager
->get(\TYPO3\CMS\Extbase\Persistence\Generic\LazyObjectStorage
::class, $parentObject, $propertyName, $fieldValue);
356 if (empty($fieldValue)) {
359 $result = $this->objectManager
->get(\TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy
::class, $parentObject, $propertyName, $fieldValue);
363 $result = $this->fetchRelatedEager($parentObject, $propertyName, $fieldValue);
369 * Fetches the related objects from the storage backend.
371 * @param DomainObjectInterface $parentObject The object instance this proxy is part of
372 * @param string $propertyName The name of the proxied property in it's parent
373 * @param mixed $fieldValue The raw field value.
376 protected function fetchRelatedEager(DomainObjectInterface
$parentObject, $propertyName, $fieldValue = '')
378 return $fieldValue === '' ?
$this->getEmptyRelationValue($parentObject, $propertyName) : $this->getNonEmptyRelationValue($parentObject, $propertyName, $fieldValue);
382 * @param DomainObjectInterface $parentObject
383 * @param string $propertyName
386 protected function getEmptyRelationValue(DomainObjectInterface
$parentObject, $propertyName)
388 $columnMap = $this->getDataMap(get_class($parentObject))->getColumnMap($propertyName);
389 $relatesToOne = $columnMap->getTypeOfRelation() == ColumnMap
::RELATION_HAS_ONE
;
390 return $relatesToOne ?
null : [];
394 * @param DomainObjectInterface $parentObject
395 * @param string $propertyName
396 * @param string $fieldValue
397 * @return Persistence\QueryResultInterface
399 protected function getNonEmptyRelationValue(DomainObjectInterface
$parentObject, $propertyName, $fieldValue)
401 $query = $this->getPreparedQuery($parentObject, $propertyName, $fieldValue);
402 return $query->execute();
406 * Builds and returns the prepared query, ready to be executed.
408 * @param DomainObjectInterface $parentObject
409 * @param string $propertyName
410 * @param string $fieldValue
411 * @return Persistence\QueryInterface
413 protected function getPreparedQuery(DomainObjectInterface
$parentObject, $propertyName, $fieldValue = '')
415 $columnMap = $this->getDataMap(get_class($parentObject))->getColumnMap($propertyName);
416 $type = $this->getType(get_class($parentObject), $propertyName);
417 $query = $this->queryFactory
->create($type);
418 $query->getQuerySettings()->setRespectStoragePage(false);
419 $query->getQuerySettings()->setRespectSysLanguage(false);
420 if ($columnMap->getTypeOfRelation() === ColumnMap
::RELATION_HAS_MANY
) {
421 if ($columnMap->getChildSortByFieldName() !== null) {
422 $query->setOrderings([$columnMap->getChildSortByFieldName() => Persistence\QueryInterface
::ORDER_ASCENDING
]);
424 } elseif ($columnMap->getTypeOfRelation() === ColumnMap
::RELATION_HAS_AND_BELONGS_TO_MANY
) {
425 $query->setSource($this->getSource($parentObject, $propertyName));
426 if ($columnMap->getChildSortByFieldName() !== null) {
427 $query->setOrderings([$columnMap->getChildSortByFieldName() => Persistence\QueryInterface
::ORDER_ASCENDING
]);
430 $query->matching($this->getConstraint($query, $parentObject, $propertyName, $fieldValue, $columnMap->getRelationTableMatchFields()));
435 * Builds and returns the constraint for multi value properties.
437 * @param Persistence\QueryInterface $query
438 * @param DomainObjectInterface $parentObject
439 * @param string $propertyName
440 * @param string $fieldValue
441 * @param array $relationTableMatchFields
442 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint
444 protected function getConstraint(Persistence\QueryInterface
$query, DomainObjectInterface
$parentObject, $propertyName, $fieldValue = '', $relationTableMatchFields = [])
446 $columnMap = $this->getDataMap(get_class($parentObject))->getColumnMap($propertyName);
447 if ($columnMap->getParentKeyFieldName() !== null) {
448 $constraint = $query->equals($columnMap->getParentKeyFieldName(), $parentObject);
449 if ($columnMap->getParentTableFieldName() !== null) {
450 $constraint = $query->logicalAnd(
452 $query->equals($columnMap->getParentTableFieldName(), $this->getDataMap(get_class($parentObject))->getTableName())
456 $constraint = $query->in('uid', \TYPO3\CMS\Core\Utility\GeneralUtility
::intExplode(',', $fieldValue));
458 if (!empty($relationTableMatchFields)) {
459 foreach ($relationTableMatchFields as $relationTableMatchFieldName => $relationTableMatchFieldValue) {
460 $constraint = $query->logicalAnd($constraint, $query->equals($relationTableMatchFieldName, $relationTableMatchFieldValue));
467 * Builds and returns the source to build a join for a m:n relation.
469 * @param DomainObjectInterface $parentObject
470 * @param string $propertyName
471 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source
473 protected function getSource(DomainObjectInterface
$parentObject, $propertyName)
475 $columnMap = $this->getDataMap(get_class($parentObject))->getColumnMap($propertyName);
476 $left = $this->qomFactory
->selector(null, $columnMap->getRelationTableName());
477 $childClassName = $this->getType(get_class($parentObject), $propertyName);
478 $right = $this->qomFactory
->selector($childClassName, $columnMap->getChildTableName());
479 $joinCondition = $this->qomFactory
->equiJoinCondition($columnMap->getRelationTableName(), $columnMap->getChildKeyFieldName(), $columnMap->getChildTableName(), 'uid');
480 $source = $this->qomFactory
->join($left, $right, Persistence\Generic\Query
::JCR_JOIN_TYPE_INNER
, $joinCondition);
485 * Returns the mapped classProperty from the identiyMap or
486 * mapResultToPropertyValue()
488 * If the field value is empty and the column map has no parent key field name,
489 * the relation will be empty. If the persistence session has a registered object of
490 * the correct type and identity (fieldValue), this function returns that object.
491 * Otherwise, it proceeds with mapResultToPropertyValue().
493 * @param DomainObjectInterface $parentObject
494 * @param string $propertyName
495 * @param mixed $fieldValue the raw field value
497 * @see mapResultToPropertyValue()
499 protected function mapObjectToClassProperty(DomainObjectInterface
$parentObject, $propertyName, $fieldValue)
501 if ($this->propertyMapsByForeignKey($parentObject, $propertyName)) {
502 $result = $this->fetchRelated($parentObject, $propertyName, $fieldValue);
503 $propertyValue = $this->mapResultToPropertyValue($parentObject, $propertyName, $result);
505 if ($fieldValue === '') {
506 $propertyValue = $this->getEmptyRelationValue($parentObject, $propertyName);
508 $propertyMetaData = $this->reflectionService
->getClassSchema(get_class($parentObject))->getProperty($propertyName);
509 if ($this->persistenceSession
->hasIdentifier($fieldValue, $propertyMetaData['type'])) {
510 $propertyValue = $this->persistenceSession
->getObjectByIdentifier($fieldValue, $propertyMetaData['type']);
512 $result = $this->fetchRelated($parentObject, $propertyName, $fieldValue);
513 $propertyValue = $this->mapResultToPropertyValue($parentObject, $propertyName, $result);
518 return $propertyValue;
522 * Checks if the relation is based on a foreign key.
524 * @param DomainObjectInterface $parentObject
525 * @param string $propertyName
526 * @return bool TRUE if the property is mapped
528 protected function propertyMapsByForeignKey(DomainObjectInterface
$parentObject, $propertyName)
530 $columnMap = $this->getDataMap(get_class($parentObject))->getColumnMap($propertyName);
531 return $columnMap->getParentKeyFieldName() !== null;
535 * Returns the given result as property value of the specified property type.
537 * @param DomainObjectInterface $parentObject
538 * @param string $propertyName
539 * @param mixed $result The result
542 public function mapResultToPropertyValue(DomainObjectInterface
$parentObject, $propertyName, $result)
544 $propertyValue = null;
545 if ($result instanceof Persistence\Generic\LoadingStrategyInterface
) {
546 $propertyValue = $result;
548 $propertyMetaData = $this->reflectionService
->getClassSchema(get_class($parentObject))->getProperty($propertyName);
549 if (in_array($propertyMetaData['type'], ['array', 'ArrayObject', 'SplObjectStorage', \TYPO3\CMS\Extbase\Persistence\ObjectStorage
::class], true)) {
551 foreach ($result as $value) {
554 if ($propertyMetaData['type'] === 'ArrayObject') {
555 $propertyValue = new \
ArrayObject($objects);
556 } elseif (in_array($propertyMetaData['type'], [\TYPO3\CMS\Extbase\Persistence\ObjectStorage
::class], true)) {
557 $propertyValue = new Persistence\
ObjectStorage();
558 foreach ($objects as $object) {
559 $propertyValue->attach($object);
561 $propertyValue->_memorizeCleanState();
563 $propertyValue = $objects;
565 } elseif (strpbrk($propertyMetaData['type'], '_\\') !== false) {
566 if (is_object($result) && $result instanceof Persistence\QueryResultInterface
) {
567 $propertyValue = $result->getFirst();
569 $propertyValue = $result;
573 return $propertyValue;
577 * Counts the number of related objects assigned to a property of a parent object
579 * @param DomainObjectInterface $parentObject The object instance this proxy is part of
580 * @param string $propertyName The name of the proxied property in it's parent
581 * @param mixed $fieldValue The raw field value.
584 public function countRelated(DomainObjectInterface
$parentObject, $propertyName, $fieldValue = '')
586 $query = $this->getPreparedQuery($parentObject, $propertyName, $fieldValue);
587 return $query->execute()->count();
591 * Delegates the call to the Data Map.
592 * Returns TRUE if the property is persistable (configured in $TCA)
594 * @param string $className The property name
595 * @param string $propertyName The property name
596 * @return bool TRUE if the property is persistable (configured in $TCA)
598 public function isPersistableProperty($className, $propertyName)
600 $dataMap = $this->getDataMap($className);
601 return $dataMap->isPersistableProperty($propertyName);
605 * Returns a data map for a given class name
607 * @param string $className The class name you want to fetch the Data Map for
608 * @throws Persistence\Generic\Exception
609 * @return DataMap The data map
611 public function getDataMap($className)
613 if (!is_string($className) ||
$className === '') {
614 throw new Persistence\Generic\
Exception('No class name was given to retrieve the Data Map for.', 1251315965);
616 if (!isset($this->dataMaps
[$className])) {
617 $this->dataMaps
[$className] = $this->dataMapFactory
->buildDataMap($className);
619 return $this->dataMaps
[$className];
623 * Returns the selector (table) name for a given class name.
625 * @param string $className
626 * @return string The selector name
628 public function convertClassNameToTableName($className)
630 return $this->getDataMap($className)->getTableName();
634 * Returns the column name for a given property name of the specified class.
636 * @param string $propertyName
637 * @param string $className
638 * @return string The column name
640 public function convertPropertyNameToColumnName($propertyName, $className = null)
642 if (!empty($className)) {
643 $dataMap = $this->getDataMap($className);
644 if ($dataMap !== null) {
645 $columnMap = $dataMap->getColumnMap($propertyName);
646 if ($columnMap !== null) {
647 return $columnMap->getColumnName();
651 return \TYPO3\CMS\Core\Utility\GeneralUtility
::camelCaseToLowerCaseUnderscored($propertyName);
655 * Returns the type of a child object.
657 * @param string $parentClassName The class name of the object this proxy is part of
658 * @param string $propertyName The name of the proxied property in it's parent
659 * @throws UnexpectedTypeException
660 * @return string The class name of the child object
662 public function getType($parentClassName, $propertyName)
664 $propertyMetaData = $this->reflectionService
->getClassSchema($parentClassName)->getProperty($propertyName);
665 if (!empty($propertyMetaData['elementType'])) {
666 $type = $propertyMetaData['elementType'];
667 } elseif (!empty($propertyMetaData['type'])) {
668 $type = $propertyMetaData['type'];
670 throw new UnexpectedTypeException('Could not determine the child object type.', 1251315967);
676 * Returns a plain value, i.e. objects are flattened out if possible.
677 * Multi value objects or arrays will be converted to a comma-separated list for use in IN SQL queries.
679 * @param mixed $input The value that will be converted.
680 * @param ColumnMap $columnMap Optional column map for retrieving the date storage format.
681 * @param callable $parseStringValueCallback Optional callback method that will be called for string values. Can be used to do database quotation.
682 * @param array $parseStringValueCallbackParameters Additional parameters that will be passed to the callabck as second parameter.
683 * @throws \InvalidArgumentException
684 * @throws UnexpectedTypeException
687 public function getPlainValue($input, $columnMap = null, $parseStringValueCallback = null, array $parseStringValueCallbackParameters = [])
689 if ($input === null) {
692 if ($input instanceof Persistence\Generic\LazyLoadingProxy
) {
693 $input = $input->_loadRealInstance();
696 if (is_bool($input)) {
697 $parameter = (int)$input;
698 } elseif (is_int($input)) {
700 } elseif ($input instanceof \DateTime
) {
701 if (!is_null($columnMap) && !is_null($columnMap->getDateTimeStorageFormat())) {
702 $storageFormat = $columnMap->getDateTimeStorageFormat();
703 $timeZoneToStore = clone $input;
704 // set to UTC to store in database
705 $timeZoneToStore->setTimezone(new \
DateTimeZone('UTC'));
706 switch ($storageFormat) {
708 $parameter = $timeZoneToStore->format('Y-m-d H:i:s');
711 $parameter = $timeZoneToStore->format('Y-m-d');
714 throw new \
InvalidArgumentException('Column map DateTime format "' . $storageFormat . '" is unknown. Allowed values are datetime or date.', 1395353470);
717 $parameter = $input->format('U');
719 } elseif ($input instanceof DomainObjectInterface
) {
720 $parameter = (int)$input->getUid();
721 } elseif (TypeHandlingUtility
::isValidTypeForMultiValueComparison($input)) {
722 $plainValueArray = [];
723 foreach ($input as $inputElement) {
724 $plainValueArray[] = $this->getPlainValue($inputElement, $columnMap, $parseStringValueCallback, $parseStringValueCallbackParameters);
726 $parameter = implode(',', $plainValueArray);
727 } elseif (is_object($input)) {
728 if (TypeHandlingUtility
::isCoreType($input)) {
729 $parameter = $this->getPlainStringValue($input, $parseStringValueCallback, $parseStringValueCallbackParameters);
731 throw new UnexpectedTypeException('An object of class "' . get_class($input) . '" could not be converted to a plain value.', 1274799934);
734 $parameter = $this->getPlainStringValue($input, $parseStringValueCallback, $parseStringValueCallbackParameters);
740 * If the given callback is set the value will be passed on the the callback function.
741 * The value will be converted to a string.
743 * @param string $value The string value that should be processed. Will be passed to the callback as first parameter.
744 * @param callable $callback The data passed to call_user_func().
745 * @param array $additionalParameters Optional additional parameters passed to the callback as second argument.
748 protected function getPlainStringValue($value, $callback = null, array $additionalParameters = [])
750 if (is_callable($callback)) {
751 $value = call_user_func($callback, $value, $additionalParameters);
753 return (string)$value;