objectClass = $objectClass; list($this->uses, $this->class, $this->methods, $this->properties) = array_values( ObjectReflection::fromClass($objectClass)->read($fullUses, $fullObject, $fullMethod, $fullProperty) ); $this->resolveAnnotations(); } /** * Transform an annotation into it's object's counterpart */ public function getAttributeFromClassname(array|string $className, bool $throwOnError = true) : object|bool { foreach((array) $className as $class) { foreach (array_reverse($this->class['tags']) as $item) { if ($item['object'] instanceof $class) { return $this->instanciateAnnotationObject($item); } foreach ($this->properties as $property) { foreach ($property['tags'] as $tag) { if ($item['object'] instanceof $class) { return $this->instanciateAnnotationObject($tag); } } } foreach ($this->methods as $method) { foreach ($method['tags'] as $tag) { if ($item['object'] instanceof $class) { return $this->instanciateAnnotationObject($tag); } } } } } if ($throwOnError) { throw new \Exception(sprintf("Annotation `%s` could not be found within your object `%s`.", implode(', ', (array)$className), $this->objectClass)); } return false; } /** * Transform an annotation into it's object's counterpart */ public function getAttributeListFromClassname(array|string $className, bool $throwOnError = true) : array { $list = []; foreach((array) $className as $class) { foreach ($this->class['tags'] as $item) { if ($item['object'] instanceof $class) { $list[] = $this->instanciateAnnotationObject($item); } } foreach ($this->properties as $property) { foreach ($property['tags'] as $item) { if ($item['object'] instanceof $class) { $list[$property['name']] ??= []; $list[$property['name']][] = $this->instanciateAnnotationObject($item); } } } foreach ($this->methods as $method) { foreach ($method['tags'] as $item) { if ($item['object'] instanceof $class) { $list[$method['name']] ??= []; $list[$method['name']][] = $this->instanciateAnnotationObject($item); } } } } if ( empty($list) ) { if ($throwOnError) throw new \InvalidArgumentException("Class `$className` was not found within {$this->objectClass} uses statement (or it's children / traits)"); } return $list; } /** * @deprecated Will soon be deprecated in favour of PHP's native attributes * Transform an annotation into it's object's counterpart */ public function getAnnotationFromClassname(array|string $className, bool $throwOnError = true) : object|bool { foreach((array) $className as $class) { if ( $name = $this->uses[$class] ?? false) { foreach (array_reverse($this->class['tags']) as $item) { if ($item['tag'] === $name) { return $this->instanciateAnnotationObject($item); } foreach ($this->properties as $property) { foreach ($property['tags'] as $item) { if ($item['tag'] === $name) { return $this->instanciateAnnotationObject($item); } } } foreach ($this->methods as $method) { foreach ($method['tags'] as $item) { if ($item['tag'] === $name) { return $this->instanciateAnnotationObject($item); } } } } } } if ($throwOnError) { throw new \Exception(sprintf("Annotation `%s` could not be found within your object `%s`.", implode(', ', (array)$className), $this->objectClass)); } return false; } /** * Transform an annotation into it's object's counterpart */ public function getAnnotationListFromClassname(array|string $className, bool $throwOnError = true) : array { $list = []; foreach((array) $className as $class) { if ($name = $this->uses[$class] ?? false) { foreach ($this->class['tags'] as $item) { if ($item['tag'] === $name) { $list[] = $this->instanciateAnnotationObject($item); } } foreach ($this->properties as $property) { foreach ($property['tags'] as $item) { if ($item['tag'] === $name) { $list[$property['name']] ??= []; $list[$property['name']][] = $this->instanciateAnnotationObject($item); } } } foreach ($this->methods as $method) { foreach ($method['tags'] as $item) { if ($item['tag'] === $name) { $list[$method['name']] ??= []; $list[$method['name']][] = $this->instanciateAnnotationObject($item); } } } } } if ( empty($list) ) { if ($throwOnError) throw new \InvalidArgumentException("Class `$className` was not found within {$this->objectClass} uses statement (or it's children / traits)"); } return $list; } public function instanciateAnnotationObject(array $tagDefinition) : Annotation { if (isset($tagDefinition['object']) && $tagDefinition['object'] instanceof \Attribute) { return $tagDefinition['object']; } $arguments = $this->extractArguments($tagDefinition['arguments']); if ( false === $class = array_search($tagDefinition['tag'], $this->uses) ) { return new class() implements Annotation {}; # throw new \InvalidArgumentException("Annotation class `{$tagDefinition['tag']}` was not found within {$this->objectClass} uses statement (or it's children / traits)"); } $obj = new $class(... $arguments['constructor']); foreach($arguments['setter'] as $key => $value) { $obj->$key = $value; } return $obj; } /** * Extracts arguments from an Annotation definition, easing object's declaration. */ protected function extractArguments(array $arguments) : array { $list = [ 'setter' => [], 'constructor' => [], ]; ksort($arguments); foreach($arguments as $key => $value) { $list[ is_int($key) ? 'constructor' : 'setter' ][$key] = $value; } return $list; } protected function resolveAnnotations() { foreach($this->class['tags'] as $key => &$tag) { $tag['object'] ??= $this->instanciateAnnotationObject($tag); } foreach($this->properties as &$property) { foreach($property['tags'] as &$tag){ $tag['object'] ??= $this->instanciateAnnotationObject($tag); } } foreach($this->methods as &$method) { foreach($method['tags'] as &$tag){ $tag['object'] ??= $this->instanciateAnnotationObject($tag); } } } }