/**
* Creates new Property instance from given annotation
*
* @param string $annotationType
* @param string $annotation
* @param EntityReflection $entityReflection
* @param IMapper|null $mapper
* @return Property
* @throws InvalidAnnotationException
*/
public static function createFromAnnotation($annotationType, $annotation, EntityReflection $entityReflection, IMapper $mapper = null)
{
$aliases = $entityReflection->getAliases();
$matches = [];
$matched = preg_match('~
^(null\\|)?
((?:\\\\?[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*)+)
(\\[\\])?
(\\|null)?\\s+
(\\$[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*)
(?:\\s+=\\s*(?:
"((?:\\\\"|[^"])+)" | # double quoted string
\'((?:\\\\\'|[^\'])+)\' | # single quoted string
([^ ]*)) # unquoted value
)?
(?:\\s*\\(([^)]+)\\))?
(?:\\s+(.*)\\s*)?
~xi', $annotation, $matches);
if (!$matched) {
throw new InvalidAnnotationException("Invalid property definition given: @{$annotationType} {$annotation} in entity {$entityReflection->getName()}.");
}
$propertyType = new PropertyType($matches[2], $aliases);
$isWritable = $annotationType === 'property';
$containsCollection = $matches[3] !== '';
if ($propertyType->isBasicType() and $containsCollection) {
throw new InvalidAnnotationException("Invalid property type definition given: @{$annotationType} {$annotation} in entity {$entityReflection->getName()}. Lean Mapper doesn't support <type>[] notation for basic types.");
}
$isNullable = ($matches[1] !== '' or $matches[4] !== '');
$name = substr($matches[5], 1);
$hasDefaultValue = false;
$defaultValue = null;
if (isset($matches[6]) and $matches[6] !== '') {
$defaultValue = str_replace('\\"', '"', $matches[6]);
} elseif (isset($matches[7]) and $matches[7] !== '') {
$defaultValue = str_replace("\\'", "'", $matches[7]);
} elseif (isset($matches[8]) and $matches[8] !== '') {
$defaultValue = $matches[8];
}
if ($defaultValue !== null) {
$hasDefaultValue = true;
try {
$defaultValue = self::fixDefaultValue($defaultValue, $propertyType, $isNullable);
} catch (InvalidAnnotationException $e) {
throw new InvalidAnnotationException("Invalid property definition given: @{$annotationType} {$annotation} in entity {$entityReflection->getName()}, " . lcfirst($e->getMessage()));
}
}
$column = $mapper !== null ? $mapper->getColumn($entityReflection->getName(), $name) : $name;
if (isset($matches[9]) and $matches[9] !== '') {
$column = $matches[9];
}
$relationship = null;
$propertyMethods = null;
$propertyFilters = null;
$propertyPasses = null;
$propertyValuesEnum = null;
$customFlags = [];
$customColumn = null;
$customDefault = null;
if (isset($matches[10])) {
$flagMatches = [];
preg_match_all('~m:([a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*)\\s*(?:\\(([^)]*)\\))?~', $matches[10], $flagMatches, PREG_SET_ORDER);
foreach ($flagMatches as $match) {
$flag = $match[1];
$flagArgument = (isset($match[2]) and $match[2] !== '') ? $match[2] : null;
switch ($flag) {
case 'hasOne':
case 'hasMany':
case 'belongsToOne':
case 'belongsToMany':
if ($relationship !== null) {
throw new InvalidAnnotationException("It doesn't make sense to have multiple relationship definitions in property definition: @{$annotationType} {$annotation} in entity {$entityReflection->getName()}.");
}
$relationship = self::createRelationship($entityReflection->getName(), $propertyType, $flag, $flagArgument, $mapper);
$column = null;
if ($relationship instanceof Relationship\HasOne) {
$column = $relationship->getColumnReferencingTargetTable();
}
break;
case 'useMethods':
if ($propertyMethods !== null) {
throw new InvalidAnnotationException("Multiple m:useMethods flags found in property definition: @{$annotationType} {$annotation} in entity {$entityReflection->getName()}.");
}
$propertyMethods = new PropertyMethods($name, $isWritable, $flagArgument);
break;
case 'filter':
if ($propertyFilters !== null) {
throw new InvalidAnnotationException("Multiple m:filter flags found in property definition: @{$annotationType} {$annotation} in entity {$entityReflection->getName()}.");
}
$propertyFilters = new PropertyFilters($flagArgument);
break;
case 'passThru':
if ($propertyPasses !== null) {
throw new InvalidAnnotationException("Multiple m:passThru flags found in property definition: @{$annotationType} {$annotation} in entity {$entityReflection->getName()}.");
}
$propertyPasses = new PropertyPasses($flagArgument);
break;
case 'enum':
if ($propertyValuesEnum !== null) {
throw new InvalidAnnotationException("Multiple values enumerations found in property definition: @{$annotationType} {$annotation} in entity {$entityReflection->getName()}.");
}
if ($flagArgument === null) {
throw new InvalidAnnotationException("Parameter of m:enum flag was not found in property definition: @{$annotationType} {$annotation} in entity {$entityReflection->getName()}.");
}
$propertyValuesEnum = new PropertyValuesEnum($flagArgument, $entityReflection);
break;
case 'column':
if ($customColumn !== null) {
throw new InvalidAnnotationException("Multiple column name settings found in property definition: @{$annotationType} {$annotation} in entity {$entityReflection->getName()}.");
}
if ($flagArgument === null) {
throw new InvalidAnnotationException("Parameter of m:column flag was not found in property definition: @{$annotationType} {$annotation} in entity {$entityReflection->getName()}.");
}
$customColumn = $flagArgument;
break;
case 'default':
if ($customDefault !== null) {
throw new InvalidAnnotationException("Multiple default value settings found in property definition: @{$annotationType} {$annotation} in entity {$entityReflection->getName()}.");
}
if ($flagArgument === null) {
throw new InvalidAnnotationException("Parameter of m:default flag was not found in property definition: @{$annotationType} {$annotation} in entity {$entityReflection->getName()}.");
}
$matched = preg_match('~
^\\s*(?:
"((?:\\\\"|[^"])+)" | # double quoted string
\'((?:\\\\\'|[^\'])+)\' | # single quoted string
([^ ]*) # unquoted value
)
~xi', $flagArgument, $matches);
if (!$matched) {
throw new \Exception();
}
if (isset($matches[1]) and $matches[1] !== '') {
$customDefault = str_replace('\\"', '"', $matches[1]);
} elseif (isset($matches[2]) and $matches[2] !== '') {
$customDefault = str_replace("\\'", "'", $matches[2]);
} elseif (isset($matches[3]) and $matches[3] !== '') {
$customDefault = $matches[3];
}
break;
default:
if (array_key_exists($flag, $customFlags)) {
throw new InvalidAnnotationException("Multiple m:{$flag} flags found in property definition: @{$annotationType} {$annotation} in entity {$entityReflection->getName()}.");
}
$customFlags[$flag] = $flagArgument;
}
}
}
$column = $customColumn ?: $column;
$defaultValue = $customDefault ?: $defaultValue;
return new Property($name, $entityReflection, $column, $propertyType, $isWritable, $isNullable, $containsCollection, $hasDefaultValue, $defaultValue, $relationship, $propertyMethods, $propertyFilters, $propertyPasses, $propertyValuesEnum, $customFlags);
}