/** * @throws RuntimeException * @param string $className * @param string $propertyName * @return string */ public function getTargetEntity($className, $propertyName) { $propertyMetaData = $this->reflectionService->getClassSchema($className)->getProperty($propertyName); if (!empty($propertyMetaData['elementType'])) { $type = $propertyMetaData['elementType']; } elseif (!empty($propertyMetaData['type'])) { $type = $propertyMetaData['type']; } else { throw new \RuntimeException("Cannot guess target entity from {$className}#{$propertyName} using Extbase metadata."); } return $type; }
/** * Builds a data map by adding column maps for all the configured columns in the $TCA. * It also resolves the type of values the column is holding and the typo of relation the column * represents. * * @param string $className The class name you want to fetch the Data Map for * @return Tx_Extbase_Persistence_Mapper_DataMap The data map */ public function buildDataMap($className) { if (!class_exists($className)) { throw new Tx_Extbase_Persistence_Exception_InvalidClass('Could not find class definition for name "' . $className . '". This could be caused by a mis-spelling of the class name in the class definition.'); } $recordType = NULL; $subclasses = array(); $tableName = strtolower($className); $columnMapping = array(); $extbaseFrameworkConfiguration = Tx_Extbase_Dispatcher::getExtbaseFrameworkConfiguration(); $classSettings = $extbaseFrameworkConfiguration['persistence']['classes'][$className]; if ($classSettings !== NULL) { if (isset($classSettings['subclasses']) && is_array($classSettings['subclasses'])) { $subclasses = $classSettings['subclasses']; } if (isset($classSettings['mapping']['recordType']) && strlen($classSettings['mapping']['recordType']) > 0) { $recordType = $classSettings['mapping']['recordType']; } if (isset($classSettings['mapping']['tableName']) && strlen($classSettings['mapping']['tableName']) > 0) { $tableName = $classSettings['mapping']['tableName']; } $classHierachy = array_merge(array($className), class_parents($className)); foreach ($classHierachy as $currentClassName) { if (in_array($currentClassName, array('Tx_Extbase_DomainObject_AbstractEntity', 'Tx_Extbase_DomainObject_AbstractValueObject'))) { break; } $currentTableName = strtolower($currentClassName); $currentClassSettings = $extbaseFrameworkConfiguration['persistence']['classes'][$currentClassName]; if ($currentClassSettings !== NULL) { if (isset($currentClassSettings['mapping']['columns']) && is_array($currentClassSettings['mapping']['columns'])) { $columnMapping = t3lib_div::array_merge_recursive_overrule($columnMapping, $currentClassSettings['mapping']['columns'], 0, FALSE); // FALSE means: do not include empty values form 2nd array } } } } $dataMap = t3lib_div::makeInstance('Tx_Extbase_Persistence_Mapper_DataMap', $className, $tableName, $recordType, $subclasses); $dataMap = $this->addMetaDataColumnNames($dataMap, $tableName); // $classPropertyNames = $this->reflectionService->getClassPropertyNames($className); $tcaColumnsDefinition = $this->getColumnsDefinition($tableName); $tcaColumnsDefinition = t3lib_div::array_merge_recursive_overrule($tcaColumnsDefinition, $columnMapping); // TODO Is this is too powerful? foreach ($tcaColumnsDefinition as $columnName => $columnDefinition) { if (isset($columnDefinition['mapOnProperty'])) { $propertyName = $columnDefinition['mapOnProperty']; } else { $propertyName = Tx_Extbase_Utility_Extension::convertUnderscoredToLowerCamelCase($columnName); } // if (in_array($propertyName, $classPropertyNames)) { // TODO Enable check for property existance $columnMap = new Tx_Extbase_Persistence_Mapper_ColumnMap($columnName, $propertyName); $propertyMetaData = $this->reflectionService->getClassSchema($className)->getProperty($propertyName); $columnMap = $this->setRelations($columnMap, $columnDefinition['config'], $propertyMetaData); $dataMap->addColumnMap($columnMap); // } } // debug($dataMap); return $dataMap; }
/** * Returns the type of a child object. * * @param string $parentClassName The class name of the object this proxy is part of * @param string $propertyName The name of the proxied property in it's parent * @return string The class name of the child object */ public function getType($parentClassName, $propertyName) { $propertyMetaData = $this->reflectionService->getClassSchema($parentClassName)->getProperty($propertyName); if (!empty($propertyMetaData['elementType'])) { $type = $propertyMetaData['elementType']; } elseif (!empty($propertyMetaData['type'])) { $type = $propertyMetaData['type']; } else { throw new Tx_Extbase_Persistence_Exception_UnexpectedTypeException('Could not determine the child object type.', 1251315967); } return $type; }
/** * Remove related objects * * @param Tx_Extbase_DomainObject_DomainObjectInterface $object The object to scanned for related objects * @return void */ protected function removeRelatedObjects(Tx_Extbase_DomainObject_DomainObjectInterface $object) { $className = get_class($object); $dataMap = $this->dataMapper->getDataMap($className); $classSchema = $this->reflectionService->getClassSchema($className); $properties = $object->_getProperties(); foreach ($properties as $propertyName => $propertyValue) { $columnMap = $dataMap->getColumnMap($propertyName); $propertyMetaData = $classSchema->getProperty($propertyName); if ($propertyMetaData['cascade'] === 'remove') { if ($columnMap->getTypeOfRelation() === Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_MANY) { foreach ($propertyValue as $containedObject) { $this->removeObject($containedObject); } } elseif ($propertyValue instanceof Tx_Extbase_DomainObject_DomainObjectInterface) { $this->removeObject($propertyValue); } } } }
/** * Sets the data type of this argument's value * * @param string $dataType The data type. Can be either a built-in type such as "Text" or "Integer" or a fully qualified object name * @return Tx_Extbase_MVC_Controller_Argument $this * @api */ public function setDataType($dataType) { $this->dataType = $dataType; $this->dataTypeClassSchema = $this->reflectionService->getClassSchema($dataType); return $this; }
/** * Maps the given properties to the target object WITHOUT VALIDATING THE RESULT. * If the properties could be set, this method returns TRUE, otherwise FALSE. * Returning TRUE does not mean that the target object is valid and secure! * * Only use this method if you're sure that you don't need validation! * * @param array $propertyNames Names of the properties to map. * @param mixed $source Source containing the properties to map to the target object. Must either be an array, ArrayObject or any other object. * @param object $target The target object * @param array $optionalPropertyNames Names of optional properties. If a property is specified here and it doesn't exist in the source, no error is issued. * @return boolean TRUE if the properties could be mapped, otherwise FALSE * @see mapAndValidate() * @api */ public function map(array $propertyNames, $source, $target, $optionalPropertyNames = array()) { if (!is_object($source) && !is_array($source)) { throw new Tx_Extbase_Property_Exception_InvalidSource('The source object must be a valid object or array, ' . gettype($target) . ' given.', 1187807099); } if (is_string($target) && strpos($target, '_') !== FALSE) { return $this->transformToObject($source, $target, '--none--'); } if (!is_object($target) && !is_array($target)) { throw new Tx_Extbase_Property_Exception_InvalidTarget('The target object must be a valid object or array, ' . gettype($target) . ' given.', 1187807099); } $this->mappingResults = new Tx_Extbase_Property_MappingResults(); if (is_object($target)) { $targetClassSchema = $this->reflectionService->getClassSchema(get_class($target)); } else { $targetClassSchema = NULL; } foreach ($propertyNames as $propertyName) { $propertyValue = NULL; if (is_array($source) || $source instanceof ArrayAccess) { if (isset($source[$propertyName])) { $propertyValue = $source[$propertyName]; } } else { $propertyValue = Tx_Extbase_Reflection_ObjectAccess::getProperty($source, $propertyName); } if ($propertyValue === NULL && !in_array($propertyName, $optionalPropertyNames)) { $this->mappingResults->addError(new Tx_Extbase_Error_Error("Required property '{$propertyName}' does not exist.", 1236785359), $propertyName); } else { if ($targetClassSchema !== NULL && $targetClassSchema->hasProperty($propertyName)) { $propertyMetaData = $targetClassSchema->getProperty($propertyName); if (in_array($propertyMetaData['type'], array('array', 'ArrayObject', 'Tx_Extbase_Persistence_ObjectStorage')) && (strpos($propertyMetaData['elementType'], '_') !== FALSE || $propertyValue === '')) { $objects = array(); if (is_array($propertyValue)) { foreach ($propertyValue as $value) { $objects[] = $this->transformToObject($value, $propertyMetaData['elementType'], $propertyName); } } // make sure we hand out what is expected if ($propertyMetaData['type'] === 'ArrayObject') { $propertyValue = new ArrayObject($objects); } elseif ($propertyMetaData['type'] === 'Tx_Extbase_Persistence_ObjectStorage') { $propertyValue = new Tx_Extbase_Persistence_ObjectStorage(); foreach ($objects as $object) { $propertyValue->attach($object); } } else { $propertyValue = $objects; } } elseif ($propertyMetaData['type'] === 'DateTime' || strpos($propertyMetaData['type'], '_') !== FALSE) { $propertyValue = $this->transformToObject($propertyValue, $propertyMetaData['type'], $propertyName); if ($propertyValue === NULL) { continue; } } } elseif ($targetClassSchema !== NULL) { $this->mappingResults->addError(new Tx_Extbase_Error_Error("Property '{$propertyName}' does not exist in target class schema.", 1251813614), $propertyName); } if (is_array($target)) { $target[$propertyName] = $propertyValue; } elseif (Tx_Extbase_Reflection_ObjectAccess::setProperty($target, $propertyName, $propertyValue) === FALSE) { $this->mappingResults->addError(new Tx_Extbase_Error_Error("Property '{$propertyName}' could not be set.", 1236783102), $propertyName); } } } return !$this->mappingResults->hasErrors(); }