notes/src/ObjectResolver.php

253 lines
8.4 KiB
PHP

<?php
namespace Notes;
class ObjectResolver {
const KEY_ENTITY_NAME = 01;
const KEY_COLUMN_NAME = 02;
public string $objectClass;
public array $uses;
public array $class;
public array $properties;
public array $methods;
public function __construct(string $objectClass, bool $fullUses = true, bool $fullObject = true, $fullMethod = true, $fullProperty = true)
{
$this->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);
}
}
}
}