- Totally reworked Notes to allievate most conceptions problems. Removed old annotations artifacts too
This commit is contained in:
parent
996c8fa14a
commit
61b84bfd09
|
@ -9,7 +9,9 @@
|
||||||
"email": "info@mcnd.ca"
|
"email": "info@mcnd.ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {},
|
"require": {
|
||||||
|
"mcnd/kash" : "dev-master"
|
||||||
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Notes\\": "src/"
|
"Notes\\": "src/"
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Notes;
|
||||||
|
|
||||||
|
use Notes\Common\ReflectedAttribute;
|
||||||
|
use Reflector, ReflectionClass, ReflectionProperty, ReflectionMethod;
|
||||||
|
|
||||||
|
class AttributeReader
|
||||||
|
{
|
||||||
|
const PHP_TYPES = [ "string", "int", "float", "object", "double", "closure", ];
|
||||||
|
|
||||||
|
public static function reflectAttributes(\Reflector $reflect) : array
|
||||||
|
{
|
||||||
|
$list = [];
|
||||||
|
|
||||||
|
foreach($reflect->getAttributes() as $attribute) {
|
||||||
|
try {
|
||||||
|
$list[] = new ReflectedAttribute(
|
||||||
|
tag: substr(strrchr($attribute->getName(), "\\"), 1),
|
||||||
|
object: $attribute->newInstance(),
|
||||||
|
arguments: $attribute->getArguments(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch(\Throwable $e) {
|
||||||
|
throw new \Exception(sprintf("%s for %s in file '%s'", $e->getMessage(), $reflect, static::getObjectName($reflect)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $list;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function getObjectName(Reflector $reflect) : string
|
||||||
|
{
|
||||||
|
switch(true) {
|
||||||
|
case $reflect instanceof ReflectionMethod :
|
||||||
|
case $reflect instanceof ReflectionProperty :
|
||||||
|
return $reflect->class . "::" . $reflect->name;
|
||||||
|
|
||||||
|
case $reflect instanceof ReflectionClass :
|
||||||
|
return $reflect->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \InvalidArgumentException("Given reflector is not supported within getObjectName().");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function getObjectNamespace(Reflector $reflect) : string
|
||||||
|
{
|
||||||
|
switch(true) {
|
||||||
|
case $reflect instanceof ReflectionMethod :
|
||||||
|
case $reflect instanceof ReflectionProperty :
|
||||||
|
return $reflect->getDeclaringClass()->getNamespaceName();
|
||||||
|
|
||||||
|
case $reflect instanceof ReflectionClass :
|
||||||
|
return $reflect->getNamespaceName();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \InvalidArgumentException("Given reflector is not supported within getObjectNamespace().");
|
||||||
|
}
|
||||||
|
}
|
|
@ -87,7 +87,7 @@ class CommandFetcher {
|
||||||
|
|
||||||
$class = $this->generateClassname($basename, $namespace);
|
$class = $this->generateClassname($basename, $namespace);
|
||||||
|
|
||||||
$objectResolver = new ObjectResolver($class, false, true, false, false);
|
$objectResolver = new ObjectResolver($class, true, false, false);
|
||||||
|
|
||||||
$attributes = $objectResolver->getAttributeListFromClassname( $this->annotations['object'], false ) ;
|
$attributes = $objectResolver->getAttributeListFromClassname( $this->annotations['object'], false ) ;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Notes\Common;
|
||||||
|
|
||||||
|
use Notes\Attribute\Ignore;
|
||||||
|
|
||||||
|
abstract class Reflected
|
||||||
|
{
|
||||||
|
public function hasIgnoreAttribute() : bool
|
||||||
|
{
|
||||||
|
return [] !== array_filter($this->attributes, fn($e) => $e->object instanceof Ignore);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function allowsNull() : bool
|
||||||
|
{
|
||||||
|
return empty($this->type) || $this->expectType("null");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function expectType(string $type) : bool
|
||||||
|
{
|
||||||
|
$type = strtolower($type);
|
||||||
|
|
||||||
|
foreach($this->getTypes() as $item) {
|
||||||
|
|
||||||
|
if ($type === "null") {
|
||||||
|
if ($item->type === "null" || $item->nullable) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif ($type === $item->type) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTypes() : array
|
||||||
|
{
|
||||||
|
return is_array($this->type) ? $this->type : [ $this->type ];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function typeFromReflection(\ReflectionProperty|\ReflectionParameter $property) : void
|
||||||
|
{
|
||||||
|
if ( $property->hasType() ) {
|
||||||
|
$type = $property->getType();
|
||||||
|
|
||||||
|
if ($type instanceof \ReflectionUnionType ) {
|
||||||
|
foreach($type->getTypes() as $item) {
|
||||||
|
$this->type[] = new ReflectedPropertyType($item->getName(), $item->isBuiltIn(), $item->allowsNull());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->type = new ReflectedPropertyType($type->getName(), $type->isBuiltIn(), $type->allowsNull());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Notes\Common;
|
||||||
|
|
||||||
|
class ReflectedAttribute
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public mixed $tag,
|
||||||
|
public object $object,
|
||||||
|
public array $arguments = [],
|
||||||
|
){}
|
||||||
|
}
|
|
@ -0,0 +1,149 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Notes\Common;
|
||||||
|
|
||||||
|
class ReflectedClass implements ReflectedInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public string $name,
|
||||||
|
public false|ReflectedClass $parent = false,
|
||||||
|
public array $methods = [],
|
||||||
|
public array $properties = [],
|
||||||
|
public array $attributes = [],
|
||||||
|
public array $interfaces = [],
|
||||||
|
public array $traits = [],
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function getProperties(bool $deep = true) : array
|
||||||
|
{
|
||||||
|
return $deep ? array_replace(
|
||||||
|
# $this->parent ? $this->parent->getProperties(true) : [],
|
||||||
|
$this->parent ? $this->parent->getProperties(true) : [],
|
||||||
|
$this->properties
|
||||||
|
) : $this->properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMethods(bool $deep = true) : array
|
||||||
|
{
|
||||||
|
$m = array_merge(...array_map(fn($e) => $e->getMethods(true), $this->traits));
|
||||||
|
|
||||||
|
return $deep ? array_replace(
|
||||||
|
$this->parent ? $this->parent->getMethods(true) : [],
|
||||||
|
array_merge(...array_map(fn($e) => $e->getMethods(true), $this->interfaces)),
|
||||||
|
array_merge(...array_map(fn($e) => $e->getMethods(true), $this->traits)),
|
||||||
|
$this->methods
|
||||||
|
) : $this->methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAttributes(bool $deep = true) : array
|
||||||
|
{
|
||||||
|
return $deep ? array_merge(
|
||||||
|
$this->parent ? $this->parent->getAttributes(true) : [],
|
||||||
|
array_merge(...array_map(fn($e) => $e->getAttributes(true), $this->interfaces)),
|
||||||
|
array_merge(...array_map(fn($e) => $e->getAttributes(true), $this->traits)),
|
||||||
|
$this->attributes
|
||||||
|
) : $this->attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get Attributes based on Native attributes's target
|
||||||
|
public function getClassAttributeList(array|string $className, bool $deepSearch, bool $throwOnError = true) : array
|
||||||
|
{
|
||||||
|
$list = [];
|
||||||
|
|
||||||
|
foreach((array) $className as $class) {
|
||||||
|
$reflection = new \ReflectionClass($class);
|
||||||
|
$attributes = $reflection->getAttributes();
|
||||||
|
|
||||||
|
foreach($attributes as $attribute) {
|
||||||
|
# Native PHP Attribute
|
||||||
|
if ($attribute->getName() === 'Attribute') {
|
||||||
|
if ($attribute->getTarget() && \Attribute::TARGET_CLASS) {
|
||||||
|
$list = $this->getClassAttributeListFromClassname($class, $deepSearch, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($attribute->getTarget() && \Attribute::TARGET_METHOD) {
|
||||||
|
$list = array_merge($list, $this->getMethodAttributeListFromClassname($class, $deepSearch, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($attribute->getTarget() && \Attribute::TARGET_PROPERTY) {
|
||||||
|
$list = array_merge($list, $this->getPropertyAttributeListFromClassname($class, $deepSearch, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( empty($list) && $throwOnError ) {
|
||||||
|
$className = implode(',', (array) $className);
|
||||||
|
throw new \InvalidArgumentException("Attribute(s) `$className` was not found within class {$this->name} (or it's parents / traits)");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $list;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getClassAttributeListFromClassname(array|string $className, bool $deepSearch, bool $throwOnError = true) : array
|
||||||
|
{
|
||||||
|
$list = [];
|
||||||
|
|
||||||
|
foreach((array) $className as $class) {
|
||||||
|
foreach ($this->getAttributes($deepSearch) as $item) {
|
||||||
|
if ($item->object instanceof $class) {
|
||||||
|
$list[] = $item->object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( empty($list) && $throwOnError ) {
|
||||||
|
$className = implode(',', (array) $className);
|
||||||
|
throw new \InvalidArgumentException("Attribute(s) `$className` was not found within class {$this->name} (or it's parents / traits)");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPropertyAttributeListFromClassname(array|string $className, bool $deepSearch, bool $throwOnError = true) : array
|
||||||
|
{
|
||||||
|
$list = [];
|
||||||
|
|
||||||
|
foreach((array) $className as $class) {
|
||||||
|
foreach ($this->getProperties($deepSearch) as $property) {
|
||||||
|
foreach ($property->attributes as $item) {
|
||||||
|
if ($item->object instanceof $class) {
|
||||||
|
$list[$property->name] ??= [];
|
||||||
|
$list[$property->name][] = $item->object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( empty($list) && $throwOnError ) {
|
||||||
|
$className = implode(',', (array) $className);
|
||||||
|
throw new \InvalidArgumentException("Attribute(s) `$className` was not found within properties of {$this->name} (or it's parents / traits)");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMethodAttributeListFromClassname(array|string $className, bool $deepSearch, bool $throwOnError = true) : array
|
||||||
|
{
|
||||||
|
$list = [];
|
||||||
|
|
||||||
|
foreach((array) $className as $class) {
|
||||||
|
foreach ($this->getMethods($deepSearch) as $method) {
|
||||||
|
foreach ($method->attributes as $item) {
|
||||||
|
if ($item->object instanceof $class) {
|
||||||
|
$list[$method->name] ??= [];
|
||||||
|
$list[$method->name][] = $item->object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( empty($list) && $throwOnError ) {
|
||||||
|
$className = implode(',', (array) $className);
|
||||||
|
throw new \InvalidArgumentException("Attribute(s) `$className` was not found within methods of {$this->name} (or it's parents / traits)");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $list;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Notes\Common;
|
||||||
|
|
||||||
|
interface ReflectedInterface
|
||||||
|
{
|
||||||
|
public function getAttributes() : array;
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Notes\Common;
|
||||||
|
|
||||||
|
class ReflectedMethod extends Reflected implements ReflectedInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public string $name,
|
||||||
|
public string $classname,
|
||||||
|
public false|ReflectedMethodType|\ReflectionNamedType|\ReflectionUnionType|array $type = false,
|
||||||
|
public bool $isConstructor = false,
|
||||||
|
public bool $isDestructor = false,
|
||||||
|
public bool $isAbstract = false,
|
||||||
|
public array $attributes = [],
|
||||||
|
public array $parameters = [],
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function getAttributes(): array
|
||||||
|
{
|
||||||
|
return $this->attributes;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Notes\Common;
|
||||||
|
|
||||||
|
class ReflectedMethodProperty extends ReflectedProperty
|
||||||
|
{
|
||||||
|
public int $position;
|
||||||
|
|
||||||
|
public bool $optional = false;
|
||||||
|
|
||||||
|
public bool $byReference = false;
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Notes\Common;
|
||||||
|
|
||||||
|
class ReflectedMethodType extends ReflectedPropertyType
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Notes\Common;
|
||||||
|
|
||||||
|
use Notes\Attribute\Ignore;
|
||||||
|
|
||||||
|
class ReflectedProperty extends Reflected implements ReflectedInterface, \ArrayAccess
|
||||||
|
{
|
||||||
|
public mixed $value;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
public string $name,
|
||||||
|
public false|ReflectedPropertyType|array $type = false,
|
||||||
|
public array $attributes = [],
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function getAttributes(): array
|
||||||
|
{
|
||||||
|
return $this->attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
## BACKWARD COMPATIBILITY ONLY To be removed really soon !
|
||||||
|
public function offsetExists(mixed $offset): bool
|
||||||
|
{
|
||||||
|
return isset($this->$offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetGet(mixed $offset): mixed
|
||||||
|
{
|
||||||
|
if ($offset === 'tags') {
|
||||||
|
return $this->attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->$offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetSet(mixed $offset, mixed $value): void
|
||||||
|
{
|
||||||
|
$this->$offset = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetUnset(mixed $offset): void
|
||||||
|
{
|
||||||
|
unset($this->$offset);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Notes\Common;
|
||||||
|
|
||||||
|
class ReflectedPropertyType
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public string $type,
|
||||||
|
public bool $builtIn,
|
||||||
|
public bool $nullable,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function isType(string $type) : bool
|
||||||
|
{
|
||||||
|
if ($type === "null" || $this->nullable) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->type === $type;
|
||||||
|
}
|
||||||
|
}
|
|
@ -78,9 +78,9 @@ class TaskFetcher {
|
||||||
$class = $this->generateClassname($file->getBasename(".php"), $namespace);
|
$class = $this->generateClassname($file->getBasename(".php"), $namespace);
|
||||||
|
|
||||||
# Should generate an equivalent of Ulmus's object reflection here !
|
# Should generate an equivalent of Ulmus's object reflection here !
|
||||||
$objectResolver = new ObjectResolver($class, true, true, false, true);
|
$objectResolver = new ObjectResolver($class, $this->cache);
|
||||||
|
|
||||||
foreach($objectResolver->getAttributeListFromClassname( $this->annotations['method'], false ) as $func => $cronard) {
|
foreach($objectResolver->reflectedClass->getMethodAttributeListFromClassname( $this->annotations['method'], false, false ) as $func => $cronard) {
|
||||||
foreach($cronard as $task) {
|
foreach($cronard as $task) {
|
||||||
$list[] = [ 'class' => $class, 'method' => $func, 'annotation' => $task ];
|
$list[] = [ 'class' => $class, 'method' => $func, 'annotation' => $task ];
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,9 +78,9 @@ class EventFetcher {
|
||||||
$class = $this->generateClassname($file->getBasename(".php"), $namespace);
|
$class = $this->generateClassname($file->getBasename(".php"), $namespace);
|
||||||
|
|
||||||
# Should generate an equivalent of Ulmus's object reflection here !
|
# Should generate an equivalent of Ulmus's object reflection here !
|
||||||
$objectResolver = new ObjectResolver($class, true, true, false, true);
|
$objectResolver = new ObjectResolver($class, $this->cache ?? null);
|
||||||
|
|
||||||
foreach($objectResolver->getAttributeListFromClassname( $this->annotations['method'], false ) as $func => $events) {
|
foreach($objectResolver->reflectedClass->getMethodAttributeListFromClassname($this->annotations['method'], false, false ) as $func => $events) {
|
||||||
foreach($events as $ev) {
|
foreach($events as $ev) {
|
||||||
$list[] = new \Mcnd\Event\Event(name: $ev->name, class: $class, method: $func, attribute: $ev);
|
$list[] = new \Mcnd\Event\Event(name: $ev->name, class: $class, method: $func, attribute: $ev);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,11 @@ namespace Notes;
|
||||||
|
|
||||||
use Kash\HandleCacheTrait;
|
use Kash\HandleCacheTrait;
|
||||||
use Notes\Attribute\Ignore;
|
use Notes\Attribute\Ignore;
|
||||||
|
use Notes\Common\ReflectedClass;
|
||||||
|
use Notes\Common\ReflectedMethod;
|
||||||
|
use Notes\Common\ReflectedMethodProperty;
|
||||||
|
use Notes\Common\ReflectedProperty;
|
||||||
|
use Notes\Common\ReflectedPropertyType;
|
||||||
use Psr\SimpleCache\CacheInterface;
|
use Psr\SimpleCache\CacheInterface;
|
||||||
use Reflector, ReflectionClass, ReflectionProperty, ReflectionMethod, ReflectionUnionType, ReflectionNamedType, ReflectionParameter;
|
use Reflector, ReflectionClass, ReflectionProperty, ReflectionMethod, ReflectionUnionType, ReflectionNamedType, ReflectionParameter;
|
||||||
|
|
||||||
|
@ -14,81 +19,37 @@ class ObjectReflection {
|
||||||
|
|
||||||
protected ReflectionClass $classReflection;
|
protected ReflectionClass $classReflection;
|
||||||
|
|
||||||
public AnnotationReader $annotationReader;
|
public function __construct(ReflectionClass|string $class, ? CacheInterface $cache = null) {
|
||||||
|
$this->classname = ltrim($class instanceof ReflectionClass ? $class->getName() : $class, '\\');
|
||||||
|
|
||||||
public function __construct($class, AnnotationReader $annotationReader = null, ? CacheInterface $cache = null) {
|
|
||||||
$this->classname = ltrim($class, '\\');
|
|
||||||
$this->cache = $cache;
|
$this->cache = $cache;
|
||||||
|
|
||||||
#if ( ! $this->cache || ! $this->cache->has($class) ) {
|
#if ( ! $this->cache || ! $this->cache->has($class) ) {
|
||||||
$this->classReflection = $class instanceof ReflectionClass ? $class : new ReflectionClass($class);
|
$this->classReflection = $class instanceof ReflectionClass ? $class : new ReflectionClass($class);
|
||||||
$this->annotationReader = $annotationReader ?: AnnotationReader::fromClass($class);
|
|
||||||
# }
|
# }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function fromClass($class, ? CacheInterface $cache = null) : self
|
public static function fromClass(ReflectionClass|string $class, ? CacheInterface $cache = null) : self
|
||||||
{
|
{
|
||||||
return new static($class, null, $cache);
|
return new static($class, null, $cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function read(bool $fullUses = true, bool $fullObject = true, $fullMethod = true, $fullProperty = true) : array
|
public function reflectClass() : ReflectedClass
|
||||||
{
|
{
|
||||||
return $this->handleCaching(implode('', [ $this->classname, (int)$fullObject, (int) $fullMethod, (int) $fullProperty ]), fn() => [
|
$parentClass = $this->classReflection->getParentClass();
|
||||||
'uses' => $this->gatherUses($fullUses),
|
|
||||||
'class' => $this->gatherClass($fullObject),
|
return new ReflectedClass(
|
||||||
'method' => $this->gatherMethods($fullMethod),
|
name: $this->classReflection->getName(),
|
||||||
'property' => $this->gatherProperties($fullProperty),
|
parent: $parentClass ? static::fromClass($parentClass)->reflectClass() : false,
|
||||||
]);
|
methods: $this->reflectMethods(),
|
||||||
|
properties: $this->reflectProperties(),
|
||||||
|
attributes: AttributeReader::reflectAttributes($this->classReflection),
|
||||||
|
interfaces: array_map(fn($interface) => static::fromClass($interface)->reflectClass(), array_keys($this->classReflection->getInterfaces())),
|
||||||
|
traits: array_map(fn($trait) => static::fromClass($trait)->reflectClass(), array_keys($this->classReflection->getTraits())),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function gatherUses(bool $full = true) : array
|
public function reflectProperties(int $filter =
|
||||||
{
|
|
||||||
if ( $full ) {
|
|
||||||
if ( $parentClass = $this->classReflection->getParentClass() ) {
|
|
||||||
$list = static::fromClass($parentClass)->gatherUses(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach($this->classReflection->getTraits() as $trait) {
|
|
||||||
$list = array_replace(static::fromClass($trait->name)->gatherUses(true), $list ?? []);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return array_replace($list ?? [], $this->getUsesStatements());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function gatherClass(bool $full = true) : array
|
|
||||||
{
|
|
||||||
if ( $full ) {
|
|
||||||
if ( $parentClass = $this->classReflection->getParentClass() ) {
|
|
||||||
$class = static::fromClass($parentClass)->gatherClass(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $traits = $this->classReflection->getTraits() ) {
|
|
||||||
foreach($traits as $key => $value) {
|
|
||||||
$traitTags = static::fromClass($key)->gatherClass(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $interfaces = $this->classReflection->getInterfaces() ) {
|
|
||||||
foreach($interfaces as $key => $value) {
|
|
||||||
$interfaceTags = static::fromClass($key)->gatherClass(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$itemName = function($item) {
|
|
||||||
return $item->getName();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return array_merge_recursive($class ?? [], $traitTags ?? [], $interfaceTags ?? [], [
|
|
||||||
'tags' => $this->annotationReader->getClass($this->classReflection)
|
|
||||||
] + ( ! $full ? [] : [
|
|
||||||
'traits' => array_map($itemName, $traits),
|
|
||||||
'interfaces' => array_map($itemName, $interfaces),
|
|
||||||
] ));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function gatherProperties(bool $full = true, int $filter =
|
|
||||||
ReflectionProperty::IS_PUBLIC |
|
ReflectionProperty::IS_PUBLIC |
|
||||||
ReflectionProperty::IS_PROTECTED |
|
ReflectionProperty::IS_PROTECTED |
|
||||||
ReflectionProperty::IS_PRIVATE
|
ReflectionProperty::IS_PRIVATE
|
||||||
|
@ -96,48 +57,31 @@ class ObjectReflection {
|
||||||
{
|
{
|
||||||
$defaultValues = $this->classReflection->getDefaultProperties();
|
$defaultValues = $this->classReflection->getDefaultProperties();
|
||||||
|
|
||||||
if ( $full ) {
|
|
||||||
if ( $parentClass = $this->classReflection->getParentClass() ) {
|
|
||||||
$properties = static::fromClass($parentClass)->gatherProperties($full, $filter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$list = [];
|
$list = [];
|
||||||
|
|
||||||
foreach($this->classReflection->getProperties($filter) as $property) {
|
foreach($this->classReflection->getProperties($filter) as $property) {
|
||||||
$current = [
|
$reflected = new ReflectedProperty($property->getName());
|
||||||
'name' => $property->getName()
|
|
||||||
];
|
|
||||||
|
|
||||||
# Default value can be 'null', so isset() it not suitable here
|
$reflected->attributes = AttributeReader::reflectAttributes($property);
|
||||||
if ( array_key_exists($current['name'], $defaultValues) ) {
|
|
||||||
$current['value'] = $defaultValues[ $current['name'] ];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if ( $reflected->hasIgnoreAttribute() ) {
|
||||||
if ( $property->hasType() ) {
|
|
||||||
$type = $property->getType();
|
|
||||||
|
|
||||||
if (! $type instanceof \ReflectionUnionType ) {
|
|
||||||
$current['type'] = $type->getName();
|
|
||||||
$current['builtin'] = $type->isBuiltIn();
|
|
||||||
$current['nullable'] = $type->allowsNull();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$current['tags'] = $this->annotationReader->getProperty($property);
|
|
||||||
|
|
||||||
if ( $this->ignoreElementAnnotation($current['tags']) ) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$list[ $current['name'] ] = $current;
|
# Default value can be 'null', so isset() it not suitable here
|
||||||
|
if ( array_key_exists($reflected->name, $defaultValues) ) {
|
||||||
|
$reflected->value = $defaultValues[ $reflected->name ];
|
||||||
|
}
|
||||||
|
|
||||||
|
$reflected->typeFromReflection($property);
|
||||||
|
|
||||||
|
$list[ $reflected->name ] = $reflected;
|
||||||
}
|
}
|
||||||
|
|
||||||
return array_merge($properties ?? [], $list);
|
return array_merge($properties ?? [], $list);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function gatherMethods(bool $full = true, int $filter =
|
public function reflectMethods(int $filter =
|
||||||
ReflectionMethod::IS_PUBLIC |
|
ReflectionMethod::IS_PUBLIC |
|
||||||
ReflectionMethod::IS_PROTECTED |
|
ReflectionMethod::IS_PROTECTED |
|
||||||
ReflectionMethod::IS_PRIVATE |
|
ReflectionMethod::IS_PRIVATE |
|
||||||
|
@ -147,163 +91,47 @@ class ObjectReflection {
|
||||||
{
|
{
|
||||||
$list = [];
|
$list = [];
|
||||||
|
|
||||||
if ( $full ) {
|
|
||||||
if ( $parentClass = $this->classReflection->getParentClass() ) {
|
|
||||||
$methods = static::fromClass($parentClass)->gatherMethods($full, $filter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach($this->classReflection->getMethods($filter) as $method) {
|
foreach($this->classReflection->getMethods($filter) as $method) {
|
||||||
if ( ! $full && ( $method->class !== $this->classname ) ) {
|
# Skipping parent's methods, we'll retrieve them in its own reflection
|
||||||
|
if ( $method->class !== $this->classname ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$parameters = [];
|
$reflectedMethod = new ReflectedMethod(
|
||||||
|
name: $method->getName(),
|
||||||
|
classname: $method->class,
|
||||||
|
type: $method->hasReturnType() ? $method->getReturnType() : false,
|
||||||
|
isConstructor: $method->isConstructor(),
|
||||||
|
isDestructor: $method->isDestructor(),
|
||||||
|
isAbstract: $method->isAbstract(),
|
||||||
|
attributes: AttributeReader::reflectAttributes($method),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( $reflectedMethod->hasIgnoreAttribute() ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
foreach($method->getParameters() as $parameter) {
|
foreach($method->getParameters() as $parameter) {
|
||||||
$parameters[$parameter->getName()] = [
|
$reflectedParameter = new ReflectedMethodProperty(
|
||||||
'null' => $parameter->allowsNull(),
|
name: $parameter->getName(),
|
||||||
'position' => $parameter->getPosition(),
|
attributes: AttributeReader::reflectAttributes($parameter),
|
||||||
'type' => $parameter->hasType() && $parameter->getType() instanceof \ReflectionNamedType ? $parameter->getType()->getName() : false,
|
);
|
||||||
'array' => $this->isType('array', $parameter),
|
|
||||||
'callable' => $this->isType('callable', $parameter),
|
|
||||||
'optional' => $parameter->isOptional(),
|
|
||||||
'byReference' => $parameter->isPassedByReference(),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
$current = [
|
if ( $reflectedParameter->hasIgnoreAttribute() ) {
|
||||||
'name' => $method->getName(),
|
|
||||||
'classname' => $method->class,
|
|
||||||
'type' => $method->hasReturnType() && $method->getReturnType() instanceof \ReflectionNamedType ? $method->getReturnType()->getName() : false,
|
|
||||||
'constructor' => $method->isConstructor(),
|
|
||||||
'destructor' => $method->isDestructor(),
|
|
||||||
'parameters' => $parameters,
|
|
||||||
];
|
|
||||||
|
|
||||||
$current['tags'] = $this->annotationReader->getMethod($method);
|
|
||||||
|
|
||||||
if ( $this->ignoreElementAnnotation($current['tags']) ) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$list[ $current['name'] ] = $current;
|
$reflectedParameter->position = $parameter->getPosition();
|
||||||
|
$reflectedParameter->typeFromReflection($parameter);
|
||||||
|
$reflectedParameter->byReference = $parameter->isPassedByReference();
|
||||||
|
$reflectedParameter->optional = $parameter->isOptional();
|
||||||
|
|
||||||
|
$reflectedMethod->parameters[$reflectedParameter->name] = $reflectedParameter;
|
||||||
}
|
}
|
||||||
|
|
||||||
return array_merge($methods ?? [], $list);
|
$list[$reflectedMethod->name] = $reflectedMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function ignoreElementAnnotation($tags) : bool
|
return $list;
|
||||||
{
|
|
||||||
return [] !== array_filter($tags, fn($e) => ( $e['object'] ?? null ) instanceof Ignore);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function readCode() : string
|
|
||||||
{
|
|
||||||
static $code = [];
|
|
||||||
$fileName = $this->classReflection->getFilename();
|
|
||||||
return $code[$fileName] ?? $code[$fileName] = file_get_contents($fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
# From https://www.php.net/manual/en/reflectionparameter.isarray.php
|
|
||||||
public static function isType(string $type, ReflectionParameter $reflectionParameter) : bool
|
|
||||||
{
|
|
||||||
if ( $reflectionType = $reflectionParameter->getType() ) {
|
|
||||||
$types = $reflectionType instanceof ReflectionUnionType ? $reflectionType->getTypes() : [$reflectionType];
|
|
||||||
|
|
||||||
return in_array($type, array_map(fn(ReflectionNamedType $t) => $t->getName(), $types));
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getUsesStatements() : array
|
|
||||||
{
|
|
||||||
$uses = [];
|
|
||||||
$tokens = token_get_all( $c = $this->readCode() );
|
|
||||||
|
|
||||||
while ( $token = array_shift($tokens) ) {
|
|
||||||
|
|
||||||
if ( is_array($token) ) {
|
|
||||||
list($token, $value) = $token;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($token) {
|
|
||||||
case T_CLASS:
|
|
||||||
case T_TRAIT:
|
|
||||||
case T_INTERFACE:
|
|
||||||
break 2;
|
|
||||||
|
|
||||||
case T_USE:
|
|
||||||
$isUse = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_NS_SEPARATOR:
|
|
||||||
$isNamespace = $isUse;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_NAME_QUALIFIED:
|
|
||||||
case T_STRING:
|
|
||||||
if ( $isNamespace && $latestString ) {
|
|
||||||
$statement[] = $latestString;
|
|
||||||
}
|
|
||||||
|
|
||||||
$latestString = $value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_AS:
|
|
||||||
# My\Name\Space\aClassHere `as` ClassAlias;
|
|
||||||
$replacedClass = implode("\\", array_merge($statement, [ $latestString ]));
|
|
||||||
$latestString = null;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_WHITESPACE:
|
|
||||||
case T_COMMENT:
|
|
||||||
case T_DOC_COMMENT:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '{':
|
|
||||||
# opening a sub-namespace -> \My\Name\Space\`{`OneItem, AnotherItem}
|
|
||||||
if ( $isNamespace ) {
|
|
||||||
$inNamespace = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ';';
|
|
||||||
case ',':
|
|
||||||
case '}':
|
|
||||||
if ( $isUse ) {
|
|
||||||
$clsName = ltrim(substr($latestString, strrpos($latestString, "\\") ), '\\');
|
|
||||||
if ( $replacedClass ) {
|
|
||||||
$uses[$replacedClass] = $clsName;
|
|
||||||
$replacedClass = "";
|
|
||||||
}
|
|
||||||
elseif ( $latestString ) {
|
|
||||||
$uses[implode("\\", array_merge($statement, [ $latestString ]))] = $clsName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $inNamespace ) {
|
|
||||||
$latestString = "";
|
|
||||||
|
|
||||||
# \My\Name\Space\{OneItem, AnotherItem`}` <- closing a sub-namespace
|
|
||||||
if ( $token !== "}" ) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case T_OPEN_TAG:
|
|
||||||
default:
|
|
||||||
$statement = [];
|
|
||||||
$latestString = "";
|
|
||||||
$replacedClass = null;
|
|
||||||
$isNamespace = $inNamespace = false;
|
|
||||||
$isUse = ( $isUse ?? false ) && ( $token === ',' );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $uses;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,13 @@
|
||||||
|
|
||||||
namespace Notes;
|
namespace Notes;
|
||||||
|
|
||||||
|
use Notes\Common\ReflectedClass;
|
||||||
use Psr\SimpleCache\CacheInterface;
|
use Psr\SimpleCache\CacheInterface;
|
||||||
|
|
||||||
class ObjectResolver {
|
class ObjectResolver {
|
||||||
|
|
||||||
const KEY_ENTITY_NAME = 01;
|
|
||||||
const KEY_COLUMN_NAME = 02;
|
|
||||||
|
|
||||||
public string $objectClass;
|
public string $objectClass;
|
||||||
|
|
||||||
public array $uses;
|
public ReflectedClass $reflectedClass;
|
||||||
|
|
||||||
public array $class;
|
public array $class;
|
||||||
|
|
||||||
|
@ -19,52 +16,11 @@ class ObjectResolver {
|
||||||
|
|
||||||
public array $methods;
|
public array $methods;
|
||||||
|
|
||||||
public function __construct(string $objectClass, bool $fullUses = true, bool $fullObject = true, $fullMethod = true, $fullProperty = true, ? CacheInterface $cache = null)
|
public function __construct(string $objectClass, ? CacheInterface $cache = null)
|
||||||
{
|
{
|
||||||
$this->objectClass = $objectClass;
|
$this->objectClass = $objectClass;
|
||||||
|
|
||||||
list($this->uses, $this->class, $this->methods, $this->properties) = array_values(
|
$this->reflectedClass = ObjectReflection::fromClass($objectClass, $cache)->reflectClass();
|
||||||
ObjectReflection::fromClass($objectClass, $cache)->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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -75,26 +31,26 @@ class ObjectResolver {
|
||||||
$list = [];
|
$list = [];
|
||||||
|
|
||||||
foreach((array) $className as $class) {
|
foreach((array) $className as $class) {
|
||||||
foreach ($this->class['tags'] as $item) {
|
foreach ($this->reflectedClass->getAttributes() as $item) {
|
||||||
if ($item['object'] instanceof $class) {
|
if ($item->object instanceof $class) {
|
||||||
$list[] = $this->instanciateAnnotationObject($item);
|
$list[] = $item->object;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->properties as $property) {
|
foreach ($this->reflectedClass->getProperties(true) as $property) {
|
||||||
foreach ($property['tags'] as $item) {
|
foreach ($property->attributes as $item) {
|
||||||
if ($item['object'] instanceof $class) {
|
if ($item->object instanceof $class) {
|
||||||
$list[$property['name']] ??= [];
|
$list[$property->name] ??= [];
|
||||||
$list[$property['name']][] = $this->instanciateAnnotationObject($item);
|
$list[$property->name][] = $item->object;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->methods as $method) {
|
foreach ($this->reflectedClass->getMethods(true) as $method) {
|
||||||
foreach ($method['tags'] as $item) {
|
foreach ($method->attributes as $item) {
|
||||||
if ($item['object'] instanceof $class) {
|
if ($item->object instanceof $class) {
|
||||||
$list[$method['name']] ??= [];
|
$list[$method->name] ??= [];
|
||||||
$list[$method['name']][] = $this->instanciateAnnotationObject($item);
|
$list[$method->name][] = $item->object;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,157 +62,4 @@ class ObjectResolver {
|
||||||
|
|
||||||
return $list;
|
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|\Notes\Attribute
|
|
||||||
{
|
|
||||||
if (isset($tagDefinition['object']) && $tagDefinition['object'] instanceof \Notes\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)");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
$obj = new $class(... $arguments['constructor']);
|
|
||||||
}
|
|
||||||
catch (\Throwable $e) {
|
|
||||||
$err = $e::class;
|
|
||||||
throw new $err(sprintf("An error occured trying to instanciate class definition '%s' given argument '%s' : %s", var_export($tagDefinition, true), var_export($arguments['constructor'], true), $e->getMessage()));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach($arguments['setter'] as $key => $value) {
|
|
||||||
$obj->$key = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! $obj instanceof \Notes\Attribute ) {
|
|
||||||
throw new \RuntimeException(sprintf("An error occurred trying to retrieve an Attribute def:%s from class %s", json_encode($tagDefinition), $this->objectClass));
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,11 +93,11 @@ class RouteFetcher {
|
||||||
$class = $this->generateClassname($file->getBasename(".php"), $namespace);
|
$class = $this->generateClassname($file->getBasename(".php"), $namespace);
|
||||||
$methods = null;
|
$methods = null;
|
||||||
|
|
||||||
$objectResolver = new ObjectResolver($class, true, true, false, true, $this->cache);
|
$objectResolver = new ObjectResolver($class, $this->cache);
|
||||||
|
|
||||||
if ( isset($attributes['object']) ) {
|
if ( isset($attributes['object']) ) {
|
||||||
|
|
||||||
$objects = $objectResolver->getAttributeListFromClassname($attributes['object'], false);
|
$objects = $objectResolver->reflectedClass->getClassAttributeListFromClassname($attributes['object'], true, false);
|
||||||
|
|
||||||
foreach(array_reverse($objects) as $object) {
|
foreach(array_reverse($objects) as $object) {
|
||||||
if ($object->method ?? false ) {
|
if ($object->method ?? false ) {
|
||||||
|
@ -109,7 +109,7 @@ class RouteFetcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( isset($attributes['method']) ) {
|
if ( isset($attributes['method']) ) {
|
||||||
$routeList = $objectResolver->getAttributeListFromClassname( $attributes['method'], false );
|
$routeList = $objectResolver->reflectedClass->getMethodAttributeListFromClassname( $attributes['method'], false, false );
|
||||||
|
|
||||||
foreach($routeList as $func => $routes) {
|
foreach($routeList as $func => $routes) {
|
||||||
if (is_array($routes)) {
|
if (is_array($routes)) {
|
||||||
|
|
|
@ -58,10 +58,12 @@ class SecurityHandler {
|
||||||
|
|
||||||
protected function getClassAttributes(string $annotationClass, string $className, string $methodName)/* : \Notes\Attribute|array */
|
protected function getClassAttributes(string $annotationClass, string $className, string $methodName)/* : \Notes\Attribute|array */
|
||||||
{
|
{
|
||||||
$objectResolver = new ObjectResolver($className, true, true, false, true);
|
$objectResolver = new ObjectResolver($className);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$method = $objectResolver->getAttributeListFromClassname( $annotationClass, false );
|
$method = $objectResolver->reflectedClass->getClassAttributeList( $annotationClass, true, false );
|
||||||
|
|
||||||
|
# var_dump($method);
|
||||||
}
|
}
|
||||||
catch(\Exception $e) { }
|
catch(\Exception $e) { }
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue