/** * {@inheritDoc} */ public function readExtendedMetadata($meta, array &$config) { $validator = new Validator(); $class = $this->getMetaReflectionClass($meta); // class annotations if ($annot = $this->reader->getClassAnnotation($class, self::TREE)) { if (!in_array($annot->type, $this->strategies)) { throw new InvalidMappingException("Tree type: {$annot->type} is not available."); } $config['strategy'] = $annot->type; $config['activate_locking'] = $annot->activateLocking; $config['locking_timeout'] = (int) $annot->lockingTimeout; if ($config['locking_timeout'] < 1) { throw new InvalidMappingException("Tree Locking Timeout must be at least of 1 second."); } } if ($annot = $this->reader->getClassAnnotation($class, self::CLOSURE)) { if (!class_exists($annot->class)) { throw new InvalidMappingException("Tree closure class: {$annot->class} does not exist."); } $config['closure'] = $annot->class; } // property annotations foreach ($class->getProperties() as $property) { if ($meta->isMappedSuperclass && !$property->isPrivate() || $meta->isInheritedField($property->name) || isset($meta->associationMappings[$property->name]['inherited'])) { continue; } // left if ($this->reader->getPropertyAnnotation($property, self::LEFT)) { $field = $property->getName(); if (!$meta->hasField($field)) { throw new InvalidMappingException("Unable to find 'left' - [{$field}] as mapped property in entity - {$meta->name}"); } if (!$validator->isValidField($meta, $field)) { throw new InvalidMappingException("Tree left field - [{$field}] type is not valid and must be 'integer' in class - {$meta->name}"); } $config['left'] = $field; } // right if ($this->reader->getPropertyAnnotation($property, self::RIGHT)) { $field = $property->getName(); if (!$meta->hasField($field)) { throw new InvalidMappingException("Unable to find 'right' - [{$field}] as mapped property in entity - {$meta->name}"); } if (!$validator->isValidField($meta, $field)) { throw new InvalidMappingException("Tree right field - [{$field}] type is not valid and must be 'integer' in class - {$meta->name}"); } $config['right'] = $field; } // ancestor/parent if ($this->reader->getPropertyAnnotation($property, self::PARENT)) { $field = $property->getName(); if (!$meta->isSingleValuedAssociation($field)) { throw new InvalidMappingException("Unable to find ancestor/parent child relation through ancestor field - [{$field}] in class - {$meta->name}"); } $config['parent'] = $field; } // root if ($this->reader->getPropertyAnnotation($property, self::ROOT)) { $field = $property->getName(); if (!$meta->hasField($field)) { throw new InvalidMappingException("Unable to find 'root' - [{$field}] as mapped property in entity - {$meta->name}"); } if (!$validator->isValidFieldForRoot($meta, $field)) { throw new InvalidMappingException("Tree root field - [{$field}] type is not valid and must be any of the 'integer' types or 'string' in class - {$meta->name}"); } $config['root'] = $field; } // level if ($this->reader->getPropertyAnnotation($property, self::LEVEL)) { $field = $property->getName(); if (!$meta->hasField($field)) { throw new InvalidMappingException("Unable to find 'level' - [{$field}] as mapped property in entity - {$meta->name}"); } if (!$validator->isValidField($meta, $field)) { throw new InvalidMappingException("Tree level field - [{$field}] type is not valid and must be 'integer' in class - {$meta->name}"); } $config['level'] = $field; } // path if ($pathAnnotation = $this->reader->getPropertyAnnotation($property, self::PATH)) { $field = $property->getName(); if (!$meta->hasField($field)) { throw new InvalidMappingException("Unable to find 'path' - [{$field}] as mapped property in entity - {$meta->name}"); } if (!$validator->isValidFieldForPath($meta, $field)) { throw new InvalidMappingException("Tree Path field - [{$field}] type is not valid. It must be string or text in class - {$meta->name}"); } if (strlen($pathAnnotation->separator) > 1) { throw new InvalidMappingException("Tree Path field - [{$field}] Separator {$pathAnnotation->separator} is invalid. It must be only one character long."); } $config['path'] = $field; $config['path_separator'] = $pathAnnotation->separator; $config['path_append_id'] = $pathAnnotation->appendId; $config['path_starts_with_separator'] = $pathAnnotation->startsWithSeparator; $config['path_ends_with_separator'] = $pathAnnotation->endsWithSeparator; } // path source if ($this->reader->getPropertyAnnotation($property, self::PATH_SOURCE)) { $field = $property->getName(); if (!$meta->hasField($field)) { throw new InvalidMappingException("Unable to find 'path_source' - [{$field}] as mapped property in entity - {$meta->name}"); } if (!$validator->isValidFieldForPathSource($meta, $field)) { throw new InvalidMappingException("Tree PathSource field - [{$field}] type is not valid. It can be any of the integer variants, double, float or string in class - {$meta->name}"); } $config['path_source'] = $field; } // path hash if ($this->reader->getPropertyAnnotation($property, self::PATH_HASH)) { $field = $property->getName(); if (!$meta->hasField($field)) { throw new InvalidMappingException("Unable to find 'path_hash' - [{$field}] as mapped property in entity - {$meta->name}"); } if (!$validator->isValidFieldForPathHash($meta, $field)) { throw new InvalidMappingException("Tree PathHash field - [{$field}] type is not valid. It can be any of the integer variants, double, float or string in class - {$meta->name}"); } $config['path_hash'] = $field; } // lock time if ($this->reader->getPropertyAnnotation($property, self::LOCK_TIME)) { $field = $property->getName(); if (!$meta->hasField($field)) { throw new InvalidMappingException("Unable to find 'lock_time' - [{$field}] as mapped property in entity - {$meta->name}"); } if (!$validator->isValidFieldForLockTime($meta, $field)) { throw new InvalidMappingException("Tree PathSource field - [{$field}] type is not valid. It must be \"date\" in class - {$meta->name}"); } $config['lock_time'] = $field; } } if (isset($config['activate_locking']) && $config['activate_locking'] && !isset($config['lock_time'])) { throw new InvalidMappingException("You need to map a date field as the tree lock time field to activate locking support."); } if (!$meta->isMappedSuperclass && $config) { if (isset($config['strategy'])) { if (is_array($meta->identifier) && count($meta->identifier) > 1) { throw new InvalidMappingException("Tree does not support composite identifiers in class - {$meta->name}"); } $method = 'validate' . ucfirst($config['strategy']) . 'TreeMetadata'; $validator->{$method}($meta, $config); } else { throw new InvalidMappingException("Cannot find Tree type for class: {$meta->name}"); } } }
/** * {@inheritDoc} */ public function readExtendedMetadata($meta, array &$config) { /** * @var \SimpleXmlElement $xml */ $xml = $this->_getMapping($meta->name); $xmlDoctrine = $xml; $xml = $xml->children(self::GEDMO_NAMESPACE_URI); $validator = new Validator(); if (isset($xml->tree) && $this->_isAttributeSet($xml->tree, 'type')) { $strategy = $this->_getAttribute($xml->tree, 'type'); if (!in_array($strategy, $this->strategies)) { throw new InvalidMappingException("Tree type: {$strategy} is not available."); } $config['strategy'] = $strategy; $config['activate_locking'] = $this->_getAttribute($xml->tree, 'activate-locking') === 'true' ? true : false; if ($lockingTimeout = $this->_getAttribute($xml->tree, 'locking-timeout')) { $config['locking_timeout'] = (int) $lockingTimeout; if ($config['locking_timeout'] < 1) { throw new InvalidMappingException("Tree Locking Timeout must be at least of 1 second."); } } else { $config['locking_timeout'] = 3; } } if (isset($xml->{'tree-closure'}) && $this->_isAttributeSet($xml->{'tree-closure'}, 'class')) { $class = $this->_getAttribute($xml->{'tree-closure'}, 'class'); if (!class_exists($class)) { throw new InvalidMappingException("Tree closure class: {$class} does not exist."); } $config['closure'] = $class; } if (isset($xmlDoctrine->field)) { foreach ($xmlDoctrine->field as $mapping) { $mappingDoctrine = $mapping; $mapping = $mapping->children(self::GEDMO_NAMESPACE_URI); $field = $this->_getAttribute($mappingDoctrine, 'name'); if (isset($mapping->{'tree-left'})) { if (!$validator->isValidField($meta, $field)) { throw new InvalidMappingException("Tree left field - [{$field}] type is not valid and must be 'integer' in class - {$meta->name}"); } $config['left'] = $field; } elseif (isset($mapping->{'tree-right'})) { if (!$validator->isValidField($meta, $field)) { throw new InvalidMappingException("Tree right field - [{$field}] type is not valid and must be 'integer' in class - {$meta->name}"); } $config['right'] = $field; } elseif (isset($mapping->{'tree-root'})) { if (!$validator->isValidFieldForRoot($meta, $field)) { throw new InvalidMappingException("Tree root field - [{$field}] type is not valid and must be any of the 'integer' types or 'string' in class - {$meta->name}"); } $config['root'] = $field; } elseif (isset($mapping->{'tree-level'})) { if (!$validator->isValidField($meta, $field)) { throw new InvalidMappingException("Tree level field - [{$field}] type is not valid and must be 'integer' in class - {$meta->name}"); } $config['level'] = $field; } elseif (isset($mapping->{'tree-path'})) { if (!$validator->isValidFieldForPath($meta, $field)) { throw new InvalidMappingException("Tree Path field - [{$field}] type is not valid. It must be string or text in class - {$meta->name}"); } $separator = $this->_getAttribute($mapping->{'tree-path'}, 'separator'); if (strlen($separator) > 1) { throw new InvalidMappingException("Tree Path field - [{$field}] Separator {$separator} is invalid. It must be only one character long."); } $appendId = $this->_getAttribute($mapping->{'tree-path'}, 'append_id'); if (!$appendId) { $appendId = true; } else { $appendId = strtolower($appendId) == 'false' ? false : true; } $startsWithSeparator = $this->_getAttribute($mapping->{'tree-path'}, 'starts_with_separator'); if (!$startsWithSeparator) { $startsWithSeparator = false; } else { $startsWithSeparator = strtolower($startsWithSeparator) == 'false' ? false : true; } $endsWithSeparator = $this->_getAttribute($mapping->{'tree-path'}, 'ends_with_separator'); if (!$endsWithSeparator) { $endsWithSeparator = true; } else { $endsWithSeparator = strtolower($endsWithSeparator) == 'false' ? false : true; } $config['path'] = $field; $config['path_separator'] = $separator; $config['path_append_id'] = $appendId; $config['path_starts_with_separator'] = $startsWithSeparator; $config['path_ends_with_separator'] = $endsWithSeparator; } elseif (isset($mapping->{'tree-path-source'})) { if (!$validator->isValidFieldForPathSource($meta, $field)) { throw new InvalidMappingException("Tree PathSource field - [{$field}] type is not valid. It can be any of the integer variants, double, float or string in class - {$meta->name}"); } $config['path_source'] = $field; } elseif (isset($mapping->{'tree-lock-time'})) { if (!$validator->isValidFieldForLockTime($meta, $field)) { throw new InvalidMappingException("Tree LockTime field - [{$field}] type is not valid. It must be \"date\" in class - {$meta->name}"); } $config['lock_time'] = $field; } } } if (isset($config['activate_locking']) && $config['activate_locking'] && !isset($config['lock_time'])) { throw new InvalidMappingException("You need to map a date field as the tree lock time field to activate locking support."); } if ($xmlDoctrine->getName() == 'entity' || $xmlDoctrine->getName() == 'mapped-superclass') { if (isset($xmlDoctrine->{'many-to-one'})) { foreach ($xmlDoctrine->{'many-to-one'} as $manyToOneMapping) { /** * @var \SimpleXMLElement $manyToOneMapping */ $manyToOneMappingDoctrine = $manyToOneMapping; $manyToOneMapping = $manyToOneMapping->children(self::GEDMO_NAMESPACE_URI); if (isset($manyToOneMapping->{'tree-parent'})) { $field = $this->_getAttribute($manyToOneMappingDoctrine, 'field'); $targetEntity = $meta->associationMappings[$field]['targetEntity']; $reflectionClass = new \ReflectionClass($targetEntity); if ($targetEntity != $meta->name && !$reflectionClass->isSubclassOf($meta->name)) { throw new InvalidMappingException("Unable to find ancestor/parent child relation through ancestor field - [{$field}] in class - {$meta->name}"); } $config['parent'] = $field; } } } } else { if ($xmlDoctrine->getName() == 'document') { if (isset($xmlDoctrine->{'reference-one'})) { foreach ($xmlDoctrine->{'reference-one'} as $referenceOneMapping) { /** * @var \SimpleXMLElement $referenceOneMapping */ $referenceOneMappingDoctrine = $referenceOneMapping; $referenceOneMapping = $referenceOneMapping->children(self::GEDMO_NAMESPACE_URI); if (isset($referenceOneMapping->{'tree-parent'})) { $field = $this->_getAttribute($referenceOneMappingDoctrine, 'field'); if ($this->_getAttribute($referenceOneMappingDoctrine, 'target-document') != $meta->name) { throw new InvalidMappingException("Unable to find ancestor/parent child relation through ancestor field - [{$field}] in class - {$meta->name}"); } $config['parent'] = $field; } } } } } if (!$meta->isMappedSuperclass && $config) { if (isset($config['strategy'])) { if (is_array($meta->identifier) && count($meta->identifier) > 1) { throw new InvalidMappingException("Tree does not support composite identifiers in class - {$meta->name}"); } $method = 'validate' . ucfirst($config['strategy']) . 'TreeMetadata'; $validator->{$method}($meta, $config); } else { throw new InvalidMappingException("Cannot find Tree type for class: {$meta->name}"); } } }
/** * {@inheritDoc} */ public function readExtendedMetadata($meta, array &$config) { $mapping = $this->_getMapping($meta->name); $validator = new Validator(); if (isset($mapping['gedmo'])) { $classMapping = $mapping['gedmo']; if (isset($classMapping['tree']['type'])) { $strategy = $classMapping['tree']['type']; if (!in_array($strategy, $this->strategies)) { throw new InvalidMappingException("Tree type: {$strategy} is not available."); } $config['strategy'] = $strategy; $config['activate_locking'] = isset($classMapping['tree']['activateLocking']) ? $classMapping['tree']['activateLocking'] : false; $config['locking_timeout'] = isset($classMapping['tree']['lockingTimeout']) ? (int) $classMapping['tree']['lockingTimeout'] : 3; if ($config['locking_timeout'] < 1) { throw new InvalidMappingException("Tree Locking Timeout must be at least of 1 second."); } } if (isset($classMapping['tree']['closure'])) { $class = $classMapping['tree']['closure']; if (!class_exists($class)) { throw new InvalidMappingException("Tree closure class: {$class} does not exist."); } $config['closure'] = $class; } } if (isset($mapping['fields'])) { foreach ($mapping['fields'] as $field => $fieldMapping) { if (isset($fieldMapping['gedmo'])) { if (in_array('treeLeft', $fieldMapping['gedmo'])) { if (!$validator->isValidField($meta, $field)) { throw new InvalidMappingException("Tree left field - [{$field}] type is not valid and must be 'integer' in class - {$meta->name}"); } $config['left'] = $field; } elseif (in_array('treeRight', $fieldMapping['gedmo'])) { if (!$validator->isValidField($meta, $field)) { throw new InvalidMappingException("Tree right field - [{$field}] type is not valid and must be 'integer' in class - {$meta->name}"); } $config['right'] = $field; } elseif (in_array('treeLevel', $fieldMapping['gedmo'])) { if (!$validator->isValidField($meta, $field)) { throw new InvalidMappingException("Tree level field - [{$field}] type is not valid and must be 'integer' in class - {$meta->name}"); } $config['level'] = $field; } elseif (in_array('treeRoot', $fieldMapping['gedmo'])) { if (!$validator->isValidFieldForRoot($meta, $field)) { throw new InvalidMappingException("Tree root field - [{$field}] type is not valid and must be any of the 'integer' types or 'string' in class - {$meta->name}"); } $config['root'] = $field; } elseif (in_array('treePath', $fieldMapping['gedmo']) || isset($fieldMapping['gedmo']['treePath'])) { if (!$validator->isValidFieldForPath($meta, $field)) { throw new InvalidMappingException("Tree Path field - [{$field}] type is not valid. It must be string or text in class - {$meta->name}"); } $treePathInfo = isset($fieldMapping['gedmo']['treePath']) ? $fieldMapping['gedmo']['treePath'] : $fieldMapping['gedmo'][array_search('treePath', $fieldMapping['gedmo'])]; if (is_array($treePathInfo) && isset($treePathInfo['separator'])) { $separator = $treePathInfo['separator']; } else { $separator = '|'; } if (strlen($separator) > 1) { throw new InvalidMappingException("Tree Path field - [{$field}] Separator {$separator} is invalid. It must be only one character long."); } $config['path'] = $field; $config['path_separator'] = $separator; } elseif (in_array('treePathSource', $fieldMapping['gedmo'])) { if (!$validator->isValidFieldForPathSource($meta, $field)) { throw new InvalidMappingException("Tree PathSource field - [{$field}] type is not valid. It can be any of the integer variants, double, float or string in class - {$meta->name}"); } $config['path_source'] = $field; } elseif (in_array('treeLockTime', $fieldMapping['gedmo'])) { if (!$validator->isValidFieldForLocktime($meta, $field)) { throw new InvalidMappingException("Tree LockTime field - [{$field}] type is not valid. It must be \"date\" in class - {$meta->name}"); } $config['lock_time'] = $field; } } } } if (isset($config['activate_locking']) && $config['activate_locking'] && !isset($config['lock_time'])) { throw new InvalidMappingException("You need to map a date|datetime|timestamp field as the tree lock time field to activate locking support."); } if (isset($mapping['manyToOne'])) { foreach ($mapping['manyToOne'] as $field => $relationMapping) { if (isset($relationMapping['gedmo'])) { if (in_array('treeParent', $relationMapping['gedmo'])) { if ($relationMapping['targetEntity'] != $meta->name) { throw new InvalidMappingException("Unable to find ancestor/parent child relation through ancestor field - [{$field}] in class - {$meta->name}"); } $config['parent'] = $field; } } } } if (!$meta->isMappedSuperclass && $config) { if (isset($config['strategy'])) { if (is_array($meta->identifier) && count($meta->identifier) > 1) { throw new InvalidMappingException("Tree does not support composite identifiers in class - {$meta->name}"); } $method = 'validate' . ucfirst($config['strategy']) . 'TreeMetadata'; $validator->{$method}($meta, $config); } else { throw new InvalidMappingException("Cannot find Tree type for class: {$meta->name}"); } } }