From 75231f32b3a38771faa7d07e16fd2a8d30eb388d Mon Sep 17 00:00:00 2001
From: Dave Mc Nicoll <info@mcnd.ca>
Date: Thu, 9 May 2024 19:49:27 +0000
Subject: [PATCH] - WIP on Notes v2.x

---
 src/Adapter/DefaultAdapterTrait.php |   2 +-
 src/Adapter/SQLite.php              |   1 -
 src/Common/EntityResolver.php       | 121 ++++++++--------------------
 src/EntityTrait.php                 |  58 ++++++-------
 src/Migration/FieldDefinition.php   |  26 +++---
 src/Repository.php                  |  48 ++++++-----
 src/Repository/RelationBuilder.php  |   4 +-
 7 files changed, 104 insertions(+), 156 deletions(-)

diff --git a/src/Adapter/DefaultAdapterTrait.php b/src/Adapter/DefaultAdapterTrait.php
index 2de4f7b..4d0d90f 100644
--- a/src/Adapter/DefaultAdapterTrait.php
+++ b/src/Adapter/DefaultAdapterTrait.php
@@ -2,7 +2,7 @@
 
 namespace Ulmus\Adapter;
 
-use Ulmus\{ConnectionAdapter, Entity\InformationSchema\Table, Migration\FieldDefinition, Repository, QueryBuilder\Sql\MysqlQueryBuilder};
+use Ulmus\{ConnectionAdapter, Entity\InformationSchema\Table, Migration\FieldDefinition, Repository, QueryBuilder\Sql\MysqlQueryBuilder, Entity};
 
 trait DefaultAdapterTrait
 {
diff --git a/src/Adapter/SQLite.php b/src/Adapter/SQLite.php
index 53ac497..6567558 100644
--- a/src/Adapter/SQLite.php
+++ b/src/Adapter/SQLite.php
@@ -64,7 +64,6 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface
     public function escapeIdentifier(string $segment, int $type) : string 
     {
         switch($type) {
-            default:
             case static::IDENTIFIER_DATABASE:
             case static::IDENTIFIER_TABLE:
             case static::IDENTIFIER_FIELD:
diff --git a/src/Common/EntityResolver.php b/src/Common/EntityResolver.php
index d0bdf8e..d21f324 100644
--- a/src/Common/EntityResolver.php
+++ b/src/Common/EntityResolver.php
@@ -2,6 +2,8 @@
 
 namespace Ulmus\Common;
 
+use Notes\Common\ReflectedClass;
+use Notes\Common\ReflectedProperty;
 use Psr\SimpleCache\CacheInterface;
 use Ulmus\Ulmus,
     Ulmus\Annotation\Classes\Table,
@@ -24,13 +26,7 @@ class EntityResolver {
 
     public string $entityClass;
 
-    public array $uses;
-
-    public array $class;
-
-    public array $properties;
-
-    public array $methods;
+    public ReflectedClass $reflectedClass;
     
     protected array $fieldList = [];
 
@@ -38,14 +34,10 @@ class EntityResolver {
     {
         $this->entityClass = $entityClass;
 
-        list($this->uses, $this->class, $this->methods, $this->properties) = array_values(
-            ObjectReflection::fromClass($entityClass, $cache)->read()
-        );
-        
-        $this->resolveAnnotations();
+        $this->reflectedClass = ObjectReflection::fromClass($entityClass, $cache)->reflectClass();
     }
 
-    public function field($name, $fieldKey = self::KEY_ENTITY_NAME, $throwException = true) : ? array
+    public function field($name, $fieldKey = self::KEY_ENTITY_NAME, $throwException = true) : ? ReflectedProperty
     {
         try{
             return $this->fieldList($fieldKey)[$name] ?? null;
@@ -68,25 +60,25 @@ class EntityResolver {
     {
         $fieldList = [];
 
-        foreach($this->properties as $item) {
-            foreach($item['tags'] ?? [] as $tag) {
-                if ( $tag['object'] instanceof Field or $tag['object'] instanceof Attribute\Property\Field ) {
-                    if ( $skipVirtual && ($tag['object'] instanceof Virtual or $tag['object'] instanceof Attribute\Property\Virtual )) {
+        foreach($this->reflectedClass->getProperties(true) as $item) {
+            foreach($item->getAttributes() as $tag) {
+                if ( $tag->object instanceof Attribute\Property\Field ) {
+                    if ( $skipVirtual && $tag->object instanceof Attribute\Property\Virtual ) {
                         break;
                     }
 
                     switch($fieldKey) {
                         case static::KEY_LC_ENTITY_NAME:
-                            $key = strtolower($item['name']);
+                            $key = strtolower($item->name);
                             break;
 
 
                         case static::KEY_ENTITY_NAME:
-                            $key = $item['name'];
+                            $key = $item->name;
                         break;
 
                         case static::KEY_COLUMN_NAME:
-                            $key = strtolower($tag['object']->name ?? $item['name']);
+                            $key = strtolower($tag->object->name ?? $item->name);
                         break;
 
                         default:
@@ -103,26 +95,24 @@ class EntityResolver {
         return $fieldList;
     }
 
-    public function relation(string $name) : ? array
+    public function relation(string $name) : array
     {
+        $property = $this->reflectedClass->getProperties(true)[$name] ?? false;
+
         try{
-            if ( null !== ( $this->properties[$name] ?? null ) ) {
-                foreach($this->properties[$name]['tags'] ?? [] as $tag) {
-                    if ( $tag['object'] instanceof Relation or $tag['object'] instanceof Attribute\Property\Relation ) {
-                        return $this->properties[$name];
+            if ( $property ) {
+                foreach($property->getAttributes() as $tag) {
+                    if ( $tag->object instanceof Relation or $tag->object instanceof Attribute\Property\Relation ) {
+                        return $property;
                     }
                 }
             }
-            
+
             return [];
         }
         catch(\Throwable $e) {
-           # if ( $throwException) {
-                throw new \InvalidArgumentException("Can't find entity relation's column named `$name` from entity {$this->entityClass}");   
-           # }
+            throw new \InvalidArgumentException("Can't find entity relation's column named `$name` from entity {$this->entityClass}");
         }
-        
-        return null;
     }
     
     public function searchFieldAnnotation(string $field, array|object|string $annotationType, bool $caseSensitive = true) : ? object
@@ -134,15 +124,17 @@ class EntityResolver {
     {
         $list = [];
 
-        $search = $caseSensitive ? $this->properties : array_change_key_case($this->properties, \CASE_LOWER);
+        $properties = $this->reflectedClass->getProperties(true);
+
+        $search = $caseSensitive ? $properties : array_change_key_case($properties, \CASE_LOWER);
 
         $annotations = is_array($annotationType) ? $annotationType : [ $annotationType ];
 
         if ( null !== ( $search[$field] ?? null ) ) {
-            foreach($search[$field]['tags'] ?? [] as $tag) {
+            foreach($search[$field]->getAttributes() as $tag) {
                 foreach($annotations as $annotation) {
-                    if ( $tag['object'] instanceof $annotation ) {
-                        $list[] = $tag['object'];
+                    if ( $tag->object instanceof $annotation ) {
+                        $list[] = $tag->object;
                     }
                 }
             }
@@ -256,6 +248,7 @@ class EntityResolver {
      */
     public function getAnnotationFromClassname(string $className, bool $throwError = true) : ? object
     {
+        exit(__FILE__);
         if ( $name = $this->uses[$className] ?? false ) {
             foreach(array_reverse($this->class['tags']) as $item) {
                 if ( $item['tag'] === $name ) {
@@ -292,9 +285,9 @@ class EntityResolver {
 
     public function getAttributeImplementing(string $interface) : ? object
     {
-        foreach (array_reverse($this->class['tags']) as $item) {
-            if ($item['object'] instanceof $interface) {
-                return $item['object'];
+        foreach (array_reverse($this->reflectedClass->getAttributes(true)) as $item) {
+            if ($item->object instanceof $interface) {
+                return $item->object;
             }
         }
 
@@ -303,61 +296,11 @@ class EntityResolver {
 
     public function instanciateAnnotationObject(array|\ReflectionAttribute $tagDefinition) : object
     {
+
         if ($tagDefinition instanceof \ReflectionAttribute) {
             $obj = $tagDefinition->newInstance();
         }
-        else {
-            $arguments = $this->extractArguments($tagDefinition['arguments']);
-
-            if (false === $class = array_search($tagDefinition['tag'], $this->uses)) {
-                throw new \InvalidArgumentException("Annotation class `{$tagDefinition['tag']}` was not found within {$this->entityClass} 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 &$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);
-            }
-        }
-    }
 }
diff --git a/src/EntityTrait.php b/src/EntityTrait.php
index fafd3f6..6d79f16 100644
--- a/src/EntityTrait.php
+++ b/src/EntityTrait.php
@@ -40,8 +40,10 @@ trait EntityTrait {
         $entityResolver = $this->resolveEntity();
 
         foreach($dataset as $key => $value) {
-            $field = $entityResolver->field(strtolower($key), EntityResolver::KEY_COLUMN_NAME, false) ?? null;
-            $field ??= $entityResolver->field(strtolower($key), EntityResolver::KEY_LC_ENTITY_NAME, false);
+            $field = $entityResolver->field(strtolower($key), EntityResolver::KEY_COLUMN_NAME, false) ?? $entityResolver->field(strtolower($key), EntityResolver::KEY_LC_ENTITY_NAME, false);
+
+            # Temp. fix, incoming patch soon
+            $type = $field->getTypes()[0];
 
             if ( $field === null ) {
                 if ($this->entityStrictFieldsDeclaration ) {
@@ -52,12 +54,12 @@ trait EntityTrait {
                 }
             }
             elseif ( is_null($value) ) {
-                $this->{$field['name']} = null;
+                $this->{$field->name} = null;
             }
-            elseif ( $field['type'] === 'array' ) {
+            elseif ( $field->expectType('array') ) {
                 if ( is_string($value)) {
                     if (substr($value, 0, 1) === "a") {
-                        $this->{$field['name']} = unserialize($value);
+                        $this->{$field->name} = unserialize($value);
                     }
                     else {
                         $data = json_decode($value, true);
@@ -66,41 +68,41 @@ trait EntityTrait {
                             throw new \Exception(sprintf("JSON error while decoding in EntityTrait : '%s' given %s", json_last_error_msg(), $value));
                         }
 
-                        $this->{$field['name']} = $data;
+                        $this->{$field->name} = $data;
                     }
                 }
                 elseif ( is_array($value) ) {
-                    $this->{$field['name']} = $value;
+                    $this->{$field->name} = $value;
                 }
             }
-            elseif ( EntityField::isScalarType($field['type']) ) {
+            elseif ( EntityField::isScalarType($type->type) ) {
 
-                if ( $field['type'] === 'string' ) {
-                    $annotation = $entityResolver->searchFieldAnnotation($field['name'], [ Attribute\Property\Field::class, Field::class ] );
+                if ( $type->type === 'string' ) {
+                    $annotation = $entityResolver->searchFieldAnnotation($field->name, [ Attribute\Property\Field::class ] );
 
                     if ( $annotation->length ?? null ) {
                         $value = mb_substr($value, 0, $annotation->length);
                     }
                 }
-                elseif ( $field['type'] === 'bool' ) {
+                elseif ( $type->type === 'bool' ) {
                     $value = (bool) $value;
                 }
 
-                $this->{$field['name']} = $value;
+                $this->{$field->name} = $value;
             }
             elseif ( $value instanceof \UnitEnum ) {
-                $this->{$field['name']} = $value;
+                $this->{$field->name} = $value;
             }
-            elseif (enum_exists($field['type'])) {
-                $this->{$field['name']} = $field['type']::from($value);
+            elseif (enum_exists($type->type)) {
+                $this->{$field->name} = $type->type::from($value);
             }
-            elseif ( ! $field['builtin'] ) {
+            elseif ( ! $type->builtIn ) {
                 try {
-                    $this->{$field['name']} = Ulmus::instanciateObject($field['type'], [ $value ]);
+                    $this->{$field->name} = Ulmus::instanciateObject($type->type, [ $value ]);
                 }
                 catch(\Error $e) {
-                    $f = $field['type'];
-                    throw new \Error(sprintf("%s for class '%s' on field '%s'", $e->getMessage(), get_class($this), $field['name']));
+                    $f = $type->type;
+                    throw new \Error(sprintf("%s for class '%s' on field '%s'", $e->getMessage(), get_class($this), $field->name));
                 }
             }
 
@@ -123,9 +125,9 @@ trait EntityTrait {
     #[Ignore]
     public function resetVirtualProperties() : self
     {
-        foreach($this->resolveEntity()->properties as $prop => $property) {
-            foreach($property['tags'] as $tag) {
-                if ( in_array(strtolower($tag['tag']), [ 'relation', 'join', 'virtual' ] ) ) {
+        foreach($this->resolveEntity()->reflectedClass->getProperties(true) as $prop => $property) {
+            foreach($property->attributes as $tag) {
+                if ( in_array(strtolower($tag->tag), [ 'relation', 'join', 'virtual' ] ) ) {
                     unset($this->$prop);
                 }
             }
@@ -155,7 +157,7 @@ trait EntityTrait {
         $entityResolver = $this->resolveEntity();
 
         foreach($entityResolver->fieldList(Common\EntityResolver::KEY_ENTITY_NAME, true) as $key => $field) {
-            $annotation = $entityResolver->searchFieldAnnotation($key, [ Attribute\Property\Field::class, Field::class ]);
+            $annotation = $entityResolver->searchFieldAnnotation($key, [ Attribute\Property\Field::class ]);
 
             if ( isset($this->$key) ) {
                 $dataset[$annotation->name ?? $key] = $rewriteValue ?
@@ -163,13 +165,13 @@ trait EntityTrait {
                 :
                     $this->$key;
             }
-            elseif ( $field['nullable'] ) {
+            elseif ( $field->allowsNull() ) {
                 $dataset[$annotation->name ?? $key] = null;
             }
         }
 
         if ($includeRelations) {
-            foreach($entityResolver->properties as $name => $field){
+            foreach($entityResolver->reflectedClass->getProperties(true) as $name => $field){
                 $relation = $entityResolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class ] );
 
                 if ($relation) {
@@ -178,7 +180,7 @@ trait EntityTrait {
                     if ($ignore && $ignore->ignoreExport) {
                         if ( $relation->isOneToOne() ) {
                             # empty object
-                            $dataset[$name] = ( new \ReflectionClass($field['type']) )->newInstanceWithoutConstructor();
+                            $dataset[$name] = ( new \ReflectionClass($field->getTypes()[0]) )->newInstanceWithoutConstructor();
                         }
                         else {
                             # empty collection
@@ -326,7 +328,9 @@ trait EntityTrait {
     {
         $default = ( $alias === false ? '' : Repository::DEFAULT_ALIAS ); # bw compatibility, to be deprecated
 
-        return new EntityField(static::class, $name, $alias ? Ulmus::repository(static::class)->adapter->adapter()->escapeIdentifier($alias, Adapter\AdapterInterface::IDENTIFIER_FIELD) : $default, Ulmus::resolveEntity(static::class));
+        $alias = $alias ? Ulmus::repository(static::class)->adapter->adapter()->escapeIdentifier($alias, Adapter\AdapterInterface::IDENTIFIER_FIELD) : $default;
+
+        return new EntityField(static::class, $name, $alias, Ulmus::resolveEntity(static::class));
     }
 
     #[Ignore]
diff --git a/src/Migration/FieldDefinition.php b/src/Migration/FieldDefinition.php
index 5bf9a4f..6174007 100644
--- a/src/Migration/FieldDefinition.php
+++ b/src/Migration/FieldDefinition.php
@@ -2,6 +2,7 @@
 
 namespace Ulmus\Migration;
 
+use Notes\Common\ReflectedProperty;
 use Ulmus\Adapter\AdapterInterface;
 use Ulmus\Annotation\Property\Field;
 use Ulmus\Attribute;
@@ -29,25 +30,28 @@ class FieldDefinition {
 
     public AdapterInterface $adapter;
 
-    public function __construct(AdapterInterface $adapter, array $data)
+    public function __construct(AdapterInterface $adapter, ReflectedProperty $data)
     {
         $this->adapter = $adapter;
 
-        $this->name = $data['name'];
-        $this->builtIn = $data['builtin'];
-        $this->tags = $data['tags'];
+        # Patch coming soon
+        $type = $data->getTypes()[0];
 
-        if (isset($data['value'])) {
-            $this->default = $data['value'];
+        $this->name = $data->name;
+        $this->builtIn = $type->builtIn;
+        $this->tags = $data->getAttributes();
+
+        if (isset($data->value)) {
+            $this->default = $data->value;
         }
 
         $field = $this->getFieldTag();
         $adapter->whitelistAttributes($field->attributes);
 
-        $this->type = $field->type ?? $data['type'];
+        $this->type = $field->type ?? $type->type;
         $this->length = $field->length ?? null;
         $this->precision = $field->precision ?? null;
-        $this->nullable = $data['nullable'] ?: $field->nullable;
+        $this->nullable = $data->allowsNull() ?: $field->nullable;
         $this->update = $field->attributes['update'] ?? null;
     }
 
@@ -76,11 +80,11 @@ class FieldDefinition {
         ]));
     }
 
-    public function getFieldTag() : Field|Attribute\Property\Field|null
+    public function getFieldTag() : Attribute\Property\Field|null
     {
-        $field = array_filter($this->tags, fn($item) => $item['object'] instanceof Field || $item['object'] instanceof Attribute\Property\Field);
+        $field = array_filter($this->tags, fn($item) => $item->object instanceof Attribute\Property\Field);
 
-        return array_pop($field)['object'];
+        return array_pop($field)->object;
     }
 
     public function getColumnName() : ? string
diff --git a/src/Repository.php b/src/Repository.php
index 953b73a..aea8c98 100644
--- a/src/Repository.php
+++ b/src/Repository.php
@@ -133,8 +133,6 @@ class Repository
 
             return $this->deleteFromPk($entity->$pkField);
         }
-
-        return false;
     }
 
     public function destroyAll(EntityCollection $collection) : void
@@ -397,8 +395,8 @@ class Repository
         $prependField and ($prependField .= "$");
 
         foreach ($entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) {
-            if (null === $entity::resolveEntity()->searchFieldAnnotation($field['name'], [ Attribute\Property\Relation\Ignore::class, RelationIgnore::class ])) {
-                $this->select(sprintf("%s.$key as {$prependField}{$field['name']}", $this->escapeIdentifier($alias)));
+            if (null === $entity::resolveEntity()->searchFieldAnnotation($field->name, [ Attribute\Property\Relation\Ignore::class, RelationIgnore::class ])) {
+                $this->select(sprintf("%s.$key as {$prependField}{$field->name}", $this->escapeIdentifier($alias)));
             }
         }
 
@@ -410,9 +408,9 @@ class Repository
         $fieldlist = [];
 
         foreach ($entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) {
-            if (null === $entity::resolveEntity()->searchFieldAnnotation($field['name'], [ Attribute\Property\Relation\Ignore::class, RelationIgnore::class ])) {
+            if (null === $entity::resolveEntity()->searchFieldAnnotation($field->name, [ Attribute\Property\Relation\Ignore::class, RelationIgnore::class ])) {
                 $fieldlist[] = $key;
-                $fieldlist[] = $entity::field($field['name'], $this->escapeIdentifier($alias));
+                $fieldlist[] = $entity::field($field->name, $this->escapeIdentifier($alias));
             }
         }
 
@@ -625,26 +623,26 @@ class Repository
                 $this->joined[$item] = true;
             }
 
-            $annotation = $this->entityResolver->searchFieldAnnotation($item, [ Attribute\Property\Join::class, Join::class ]) ?:
-                $this->entityResolver->searchFieldAnnotation($item, [ Attribute\Property\Relation::class, Relation::class ]);
+            $annotation = $this->entityResolver->searchFieldAnnotation($item, [ Attribute\Property\Join::class  ]) ?:
+                $this->entityResolver->searchFieldAnnotation($item, [ Attribute\Property\Relation::class ]);
 
             $isRelation = ( $annotation instanceof Relation ) || ($annotation instanceof Attribute\Property\Relation);
 
             if ($isRelation && ( $annotation->isManyToMany() )) {
-                throw new Exception("Many-to-many relation can not be preloaded within joins.");
+                throw new \Exception("Many-to-many relation can not be preloaded within joins.");
             }
 
             if ( $annotation ) {
                 $alias = $annotation->alias ?? $item;
 
-                $entity = $annotation->entity ?? $this->entityResolver->properties[$item]['type'];
+                $entity = $annotation->entity ?? $this->entityResolver->reflectedClass->getProperties(true)[$item]->getTypes()[0]->type;
 
                 foreach($entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) {
-                    if ( null === $entity::resolveEntity()->searchFieldAnnotation($field['name'], [ Attribute\Property\Relation\Ignore::class, RelationIgnore::class ]) ) {
+                    if ( null === $entity::resolveEntity()->searchFieldAnnotation($field->name, [ Attribute\Property\Relation\Ignore::class ]) ) {
                         $escAlias = $this->escapeIdentifier($alias);
                         $fieldName = $this->escapeIdentifier($key);
 
-                        $name = $entity::resolveEntity()->searchFieldAnnotation($field['name'], [ Attribute\Property\Field::class, Field::class ])->name ?? $field['name'];
+                        $name = $entity::resolveEntity()->searchFieldAnnotation($field->name, [ Attribute\Property\Field::class ])->name ?? $field->name;
 
 
                         $this->select("$escAlias.$fieldName as $alias\${$name}");
@@ -654,7 +652,7 @@ class Repository
                 $this->open();
 
                 if ( ! in_array(WithOptionEnum::SkipWhere, $options)) {
-                foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Where::class, Where::class ] ) as $condition) {
+                foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Where::class ] ) as $condition) {
                     if ( is_object($condition->field) && ( $condition->field->entityClass !== $entity ) ) {
                         $this->where(is_object($condition->field) ? $condition->field : $entity::field($condition->field),  $condition->getValue(), $condition->operator);
                     }
@@ -662,13 +660,13 @@ class Repository
                 }
 
                 if ( ! in_array(WithOptionEnum::SkipHaving, $options)) {
-                    foreach ($this->entityResolver->searchFieldAnnotationList($item, [Attribute\Property\Having::class, Having::class]) as $condition) {
+                    foreach ($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Having::class ]) as $condition) {
                         $this->having(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->getValue(), $condition->operator);
                     }
                 }
 
                 if ( ! in_array(WithOptionEnum::SkipFilter, $options)) {
-                    foreach ($this->entityResolver->searchFieldAnnotationList($item, [Attribute\Property\Filter::class, Filter::class]) as $filter) {
+                    foreach ($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Filter::class ]) as $filter) {
                         call_user_func_array([$this->entityClass, $filter->method], [$this, $item, true]);
                     }
                 }
@@ -681,7 +679,7 @@ class Repository
 
                 $this->join("LEFT", $entity::resolveEntity()->tableName(), $key, $foreignKey, $alias, function($join) use ($item, $entity, $alias, $options) {
                     if (  !  in_array(WithOptionEnum::SkipJoinWhere, $options)) {
-                    foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Where::class, Where::class ]) as $condition) {
+                    foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Where::class ]) as $condition) {
                         if ( ! is_object($condition->field) ) {
                             $field = $this->entityClass::field($condition->field);
                         }
@@ -699,7 +697,7 @@ class Repository
                     }
 
                     if ( ! in_array(WithOptionEnum::SkipJoinFilter, $options) ) {
-                         foreach ($this->entityResolver->searchFieldAnnotationList($item, [Attribute\Property\FilterJoin::class, FilterJoin::class]) as $filter) {
+                         foreach ($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\FilterJoin::class ]) as $filter) {
                             call_user_func_array([$this->entityClass, $filter->method], [$join, $item, true]);
                         }
                     }
@@ -726,7 +724,7 @@ class Repository
 
         # Apply FILTER annotation to this too !
         foreach(array_filter((array) $fields) as $item) {
-            if ( $relation = $this->entityResolver->searchFieldAnnotation($item, [ Attribute\Property\Relation::class, Relation::class ]) ) {
+            if ( $relation = $this->entityResolver->searchFieldAnnotation($item, [ Attribute\Property\Relation::class ]) ) {
                 $alias = $relation->alias ?? $item;
 
                 if ( $relation->isManyToMany() ) {
@@ -747,11 +745,11 @@ class Repository
 
                 #  $relation->isManyToMany() and $repository->selectJsonEntity($relation->bridge, $relation->bridgeField, true);
 
-                foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Where::class, Where::class ]) as $condition) {
+                foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Where::class ]) as $condition) {
                     $repository->where(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->getValue(), $condition->operator);
                 }
 
-                foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Having::class, Having::class ] ) as $condition) {
+                foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Having::class ] ) as $condition) {
                     $repository->having(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->getValue(), $condition->operator);
                 }
 
@@ -778,9 +776,9 @@ class Repository
     public function loadCollectionRelation(EntityCollection $collection, array|string $fields) : void
     {
         foreach ((array)$fields as $name) {
-            if (null !== ($relation = $this->entityResolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class, Relation::class ] ))) {
-                $order = $this->entityResolver->searchFieldAnnotationList($name, [ Attribute\Property\OrderBy::class, OrderBy::class ]);
-                $where = $this->entityResolver->searchFieldAnnotationList($name, [ Attribute\Property\Where::class, Where::class ]);
+            if (null !== ($relation = $this->entityResolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class ] ))) {
+                $order = $this->entityResolver->searchFieldAnnotationList($name, [ Attribute\Property\OrderBy::class ]);
+                $where = $this->entityResolver->searchFieldAnnotationList($name, [ Attribute\Property\Where::class ]);
 
                 $baseEntity = $relation->entity ?? $relation->bridge ?? $this->entityResolver->properties[$name]['type'];
                 $baseEntityResolver = $baseEntity::resolveEntity();
@@ -791,7 +789,7 @@ class Repository
                 $repository = $baseEntity::repository();
 
                 foreach ($baseEntityResolver->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) {
-                    if (null === $baseEntityResolver->searchFieldAnnotation($field['name'], [ Attribute\Property\Relation\Ignore::class, RelationIgnore::class ])) {
+                    if (null === $baseEntityResolver->searchFieldAnnotation($field->name, [ Attribute\Property\Relation\Ignore::class ])) {
                         $repository->select($baseEntityResolver->entityClass::field($key));
                     }
                 }
@@ -953,7 +951,7 @@ class Repository
     {
         if ( null === $this->queryBuilder->getFragment(Query\Select::class) ) {
             $fields = $this->entityResolver->fieldList(EntityResolver::KEY_COLUMN_NAME, true);
-            $this->select($this->entityClass::fields(array_map(fn($f) => $f['object']->name ?? $f['name'], $fields)));
+            $this->select($this->entityClass::fields(array_map(fn($f) => $f->object->name ?? $f->name, $fields)));
         }
 
         if ( null === $this->queryBuilder->getFragment(Query\From::class) ) {
diff --git a/src/Repository/RelationBuilder.php b/src/Repository/RelationBuilder.php
index af322f8..ea98938 100644
--- a/src/Repository/RelationBuilder.php
+++ b/src/Repository/RelationBuilder.php
@@ -219,7 +219,7 @@ class RelationBuilder
                 $entity = $this->relationAnnotations($name, $annotation)['relationRelation']->entity;
             }
             else {
-                $entity = $annotation->entity ?? $this->resolver->properties[$name]['type'];
+                $entity = $annotation->entity ?? $this->resolver->reflectedClass->getProperties()[$name]->getTypes()[0]->type;
             }
 
             $name = strtolower($name);
@@ -266,7 +266,7 @@ class RelationBuilder
 
     public function oneToMany(string $name, Relation|Attribute\Property\Relation $relation) : Repository
     {
-        $baseEntity = $relation->entity ?? $this->resolver->properties[$name]['type'];
+        $baseEntity = $relation->entity ?? $this->resolver->reflectedClass->getProperties()[$name]->getTypes()[0]->type;
 
         $this->repository = $baseEntity::repository();