protected function addFieldsFromClass(Doctrine\ORM\Mapping\ClassMetadata $class, $alias, $columnAliasMap) { foreach ($class->getColumnNames() as $columnName) { $propertyName = $class->getFieldName($columnName); if ($class->isInheritedField($propertyName)) { continue; } $columnAlias = $this->platform->getSQLResultCasing($columnAliasMap[$columnName]); if (isset($this->fieldMappings[$columnAlias])) { throw new \InvalidArgumentException("The column '{$columnName}' conflicts with another column in the mapper."); } $this->addFieldResult($alias, $columnAlias, $propertyName, $class->getName()); } }
/** * Merge DoctrineClassMetadata and DataAuditClassMetadata * @param DoctrineClassMetadata $doctrineClassMetadata * @return null|ClassMetadata * @throws \InvalidArgumentException */ public function extendLoadMetadataForClass(DoctrineClassMetadata $doctrineClassMetadata) { if ($doctrineClassMetadata->isMappedSuperclass || !($classMetadata = $this->loadMetadataForClass($doctrineClassMetadata->getReflectionClass()))) { return null; } /** @var $property PropertyMetadata */ foreach ($classMetadata->propertyMetadata as $name => $property) { if ($doctrineClassMetadata->isInheritedField($name) || isset($doctrineClassMetadata->associationMappings[$property->name]['inherited'])) { unset($classMetadata->propertyMetadata[$name]); continue; } if ($doctrineClassMetadata->isCollectionValuedAssociation($name)) { $property->isCollection = true; $targetMapping = $doctrineClassMetadata->getAssociationMapping($name); if (!method_exists($targetMapping['targetEntity'], $property->method)) { throw new \InvalidArgumentException(sprintf("Method %s in Class %s is not defined. Class must implement " . "a method '__toString' or configure getMethod with Versioned annotation", $property->method, $targetMapping['targetEntity'])); } } } return $classMetadata; }
/** * @param ClassMetadata $class * @param array $entityData * @param string $revType */ private function saveRevisionEntityData($class, $entityData, $revType) { $params = array($this->getRevisionId(), $revType); $types = array(\PDO::PARAM_INT, \PDO::PARAM_STR); $fields = array(); foreach ($class->associationMappings as $field => $assoc) { if ($class->isInheritanceTypeJoined() && $class->isInheritedAssociation($field)) { continue; } if (($assoc['type'] & ClassMetadata::TO_ONE) > 0 && $assoc['isOwningSide']) { $data = isset($entityData[$field]) ? $entityData[$field] : null; $relatedId = false; if ($data !== null && $this->uow->isInIdentityMap($data)) { $relatedId = $this->uow->getEntityIdentifier($data); } $targetClass = $this->em->getClassMetadata($assoc['targetEntity']); foreach ($assoc['sourceToTargetKeyColumns'] as $sourceColumn => $targetColumn) { $fields[$sourceColumn] = true; if ($data === null) { $params[] = null; $types[] = \PDO::PARAM_STR; } else { $params[] = $relatedId ? $relatedId[$targetClass->fieldNames[$targetColumn]] : null; $types[] = $targetClass->getTypeOfColumn($targetColumn); } } } } foreach ($class->fieldNames as $field) { if (array_key_exists($field, $fields)) { continue; } if ($class->isInheritanceTypeJoined() && $class->isInheritedField($field) && !$class->isIdentifier($field)) { continue; } $params[] = isset($entityData[$field]) ? $entityData[$field] : null; $types[] = $class->fieldMappings[$field]['type']; } if ($class->isInheritanceTypeSingleTable()) { $params[] = $class->discriminatorValue; $types[] = $class->discriminatorColumn['type']; } elseif ($class->isInheritanceTypeJoined() && $class->name == $class->rootEntityName) { $params[] = $entityData[$class->discriminatorColumn['name']]; $types[] = $class->discriminatorColumn['type']; } if ($class->isInheritanceTypeJoined() && $class->name != $class->rootEntityName && count($class->parentClasses)) { if (!isset($entityData[$class->discriminatorColumn['name']])) { $entityData[$class->discriminatorColumn['name']] = $class->discriminatorValue; } $this->saveRevisionEntityData($this->em->getClassMetadata($class->parentClasses[0]), $entityData, $revType); } $this->conn->executeUpdate($this->getInsertRevisionSQL($class), $params, $types); }
/** * @param ClassMetadata $meta * @param \ReflectionProperty $property * @return bool */ protected function isInherited(ClassMetadata $meta, \ReflectionProperty $property) { return $meta->isMappedSuperclass && !$property->isPrivate() || $meta->isInheritedField($property->name) || isset($meta->associationMappings[$property->name]['inherited']); }
/** * @param ORM\Mapping\ClassMetadata $metadata * @param array $config * * @return array * * @throws Exceptions\InvalidMappingException * @throws ORM\Mapping\MappingException */ private function readExtendedMetadata(ORM\Mapping\ClassMetadata $metadata, array $config) { $class = $metadata->getReflectionClass(); // Create doctrine annotation reader $reader = $this->getDefaultAnnotationReader(); // Property annotations foreach ($class->getProperties() as $property) { if ($metadata->isMappedSuperclass && $property->isPrivate() === FALSE || $metadata->isInheritedField($property->getName()) || isset($metadata->associationMappings[$property->getName()]['inherited'])) { continue; } /** @var Mapping\Annotation\Timestampable $timestampable */ if ($timestampable = $reader->getPropertyAnnotation($property, self::EXTENSION_ANNOTATION)) { $field = $property->getName(); // No map field nor association if ($metadata->hasField($field) === FALSE && $metadata->hasAssociation($field) === FALSE && $this->configuration->useLazyAssociation() === FALSE) { if ($this->configuration->autoMapField()) { $metadata->mapField(['fieldName' => $field, 'type' => $this->configuration->dbFieldType, 'nullable' => TRUE]); } else { throw new Exceptions\InvalidMappingException("Unable to find timestampable [{$field}] as mapped property in entity - {$metadata->getName()}"); } } if ($metadata->hasField($field)) { if (!$this->isValidField($metadata, $field) && $this->configuration->useLazyAssociation() === FALSE) { throw new Exceptions\InvalidMappingException("Field - [{$field}] type is not valid and must be 'string' or a one-to-many relation in class - {$metadata->getName()}"); } } // Check for valid events if (!in_array($timestampable->on, ['update', 'create', 'change', 'delete'])) { throw new Exceptions\InvalidMappingException("Field - [{$field}] trigger 'on' is not one of [update, create, change] in class - {$metadata->getName()}"); } if ($timestampable->on === 'change') { if (!isset($timestampable->field)) { throw new Exceptions\InvalidMappingException("Missing parameters on property - {$field}, field must be set on [change] trigger in class - {$metadata->getName()}"); } if (is_array($timestampable->field) && isset($timestampable->value)) { throw new Exceptions\InvalidMappingException("Timestampable extension does not support multiple value changeset detection yet."); } $field = ['field' => $field, 'trackedField' => $timestampable->field, 'value' => is_array($timestampable->value) ? $timestampable->value : [$timestampable->value]]; } // properties are unique and mapper checks that, no risk here $config[$timestampable->on][] = $field; } } return $config; }
/** * @param ClassMetadata $class * @return string * @throws \Doctrine\DBAL\DBALException */ private function getInsertRevisionSQL($class) { if (!isset($this->insertRevisionSQL[$class->name])) { $placeholders = array('?', '?'); $tableName = $this->config->getTablePrefix() . $class->table['name'] . $this->config->getTableSuffix(); $sql = "INSERT INTO " . $tableName . " (" . $this->config->getRevisionFieldName() . ", " . $this->config->getRevisionTypeFieldName(); $fields = array(); foreach ($class->associationMappings as $field => $assoc) { if ($class->isInheritanceTypeJoined() && $class->isInheritedAssociation($field)) { continue; } if (($assoc['type'] & ClassMetadata::TO_ONE) > 0 && $assoc['isOwningSide']) { foreach ($assoc['targetToSourceKeyColumns'] as $sourceCol) { $fields[$sourceCol] = true; $sql .= ', ' . $sourceCol; $placeholders[] = '?'; } } } foreach ($class->fieldNames as $field) { if (array_key_exists($field, $fields)) { continue; } if ($class->isInheritanceTypeJoined() && $class->isInheritedField($field) && !$class->isIdentifier($field)) { continue; } $type = Type::getType($class->fieldMappings[$field]['type']); $placeholders[] = !empty($class->fieldMappings[$field]['requireSQLConversion']) ? $type->convertToDatabaseValueSQL('?', $this->platform) : '?'; $sql .= ', ' . $class->getQuotedColumnName($field, $this->platform); } if ($class->isInheritanceTypeJoined() && $class->rootEntityName == $class->name || $class->isInheritanceTypeSingleTable()) { $sql .= ', ' . $class->discriminatorColumn['name']; $placeholders[] = '?'; } $sql .= ") VALUES (" . implode(", ", $placeholders) . ")"; $this->insertRevisionSQL[$class->name] = $sql; } return $this->insertRevisionSQL[$class->name]; }