- WIP on Notes v2.x

This commit is contained in:
Dave M. 2024-05-09 19:49:27 +00:00
parent 1dd9da6eb6
commit 75231f32b3
7 changed files with 104 additions and 156 deletions

View File

@ -2,7 +2,7 @@
namespace Ulmus\Adapter; 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 trait DefaultAdapterTrait
{ {

View File

@ -64,7 +64,6 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface
public function escapeIdentifier(string $segment, int $type) : string public function escapeIdentifier(string $segment, int $type) : string
{ {
switch($type) { switch($type) {
default:
case static::IDENTIFIER_DATABASE: case static::IDENTIFIER_DATABASE:
case static::IDENTIFIER_TABLE: case static::IDENTIFIER_TABLE:
case static::IDENTIFIER_FIELD: case static::IDENTIFIER_FIELD:

View File

@ -2,6 +2,8 @@
namespace Ulmus\Common; namespace Ulmus\Common;
use Notes\Common\ReflectedClass;
use Notes\Common\ReflectedProperty;
use Psr\SimpleCache\CacheInterface; use Psr\SimpleCache\CacheInterface;
use Ulmus\Ulmus, use Ulmus\Ulmus,
Ulmus\Annotation\Classes\Table, Ulmus\Annotation\Classes\Table,
@ -24,13 +26,7 @@ class EntityResolver {
public string $entityClass; public string $entityClass;
public array $uses; public ReflectedClass $reflectedClass;
public array $class;
public array $properties;
public array $methods;
protected array $fieldList = []; protected array $fieldList = [];
@ -38,14 +34,10 @@ class EntityResolver {
{ {
$this->entityClass = $entityClass; $this->entityClass = $entityClass;
list($this->uses, $this->class, $this->methods, $this->properties) = array_values( $this->reflectedClass = ObjectReflection::fromClass($entityClass, $cache)->reflectClass();
ObjectReflection::fromClass($entityClass, $cache)->read()
);
$this->resolveAnnotations();
} }
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{ try{
return $this->fieldList($fieldKey)[$name] ?? null; return $this->fieldList($fieldKey)[$name] ?? null;
@ -68,25 +60,25 @@ class EntityResolver {
{ {
$fieldList = []; $fieldList = [];
foreach($this->properties as $item) { foreach($this->reflectedClass->getProperties(true) as $item) {
foreach($item['tags'] ?? [] as $tag) { foreach($item->getAttributes() as $tag) {
if ( $tag['object'] instanceof Field or $tag['object'] instanceof Attribute\Property\Field ) { if ( $tag->object instanceof Attribute\Property\Field ) {
if ( $skipVirtual && ($tag['object'] instanceof Virtual or $tag['object'] instanceof Attribute\Property\Virtual )) { if ( $skipVirtual && $tag->object instanceof Attribute\Property\Virtual ) {
break; break;
} }
switch($fieldKey) { switch($fieldKey) {
case static::KEY_LC_ENTITY_NAME: case static::KEY_LC_ENTITY_NAME:
$key = strtolower($item['name']); $key = strtolower($item->name);
break; break;
case static::KEY_ENTITY_NAME: case static::KEY_ENTITY_NAME:
$key = $item['name']; $key = $item->name;
break; break;
case static::KEY_COLUMN_NAME: case static::KEY_COLUMN_NAME:
$key = strtolower($tag['object']->name ?? $item['name']); $key = strtolower($tag->object->name ?? $item->name);
break; break;
default: default:
@ -103,26 +95,24 @@ class EntityResolver {
return $fieldList; return $fieldList;
} }
public function relation(string $name) : ? array public function relation(string $name) : array
{ {
$property = $this->reflectedClass->getProperties(true)[$name] ?? false;
try{ try{
if ( null !== ( $this->properties[$name] ?? null ) ) { if ( $property ) {
foreach($this->properties[$name]['tags'] ?? [] as $tag) { foreach($property->getAttributes() as $tag) {
if ( $tag['object'] instanceof Relation or $tag['object'] instanceof Attribute\Property\Relation ) { if ( $tag->object instanceof Relation or $tag->object instanceof Attribute\Property\Relation ) {
return $this->properties[$name]; return $property;
} }
} }
} }
return []; return [];
} }
catch(\Throwable $e) { 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 public function searchFieldAnnotation(string $field, array|object|string $annotationType, bool $caseSensitive = true) : ? object
@ -134,15 +124,17 @@ class EntityResolver {
{ {
$list = []; $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 ]; $annotations = is_array($annotationType) ? $annotationType : [ $annotationType ];
if ( null !== ( $search[$field] ?? null ) ) { if ( null !== ( $search[$field] ?? null ) ) {
foreach($search[$field]['tags'] ?? [] as $tag) { foreach($search[$field]->getAttributes() as $tag) {
foreach($annotations as $annotation) { foreach($annotations as $annotation) {
if ( $tag['object'] instanceof $annotation ) { if ( $tag->object instanceof $annotation ) {
$list[] = $tag['object']; $list[] = $tag->object;
} }
} }
} }
@ -256,6 +248,7 @@ class EntityResolver {
*/ */
public function getAnnotationFromClassname(string $className, bool $throwError = true) : ? object public function getAnnotationFromClassname(string $className, bool $throwError = true) : ? object
{ {
exit(__FILE__);
if ( $name = $this->uses[$className] ?? false ) { if ( $name = $this->uses[$className] ?? false ) {
foreach(array_reverse($this->class['tags']) as $item) { foreach(array_reverse($this->class['tags']) as $item) {
if ( $item['tag'] === $name ) { if ( $item['tag'] === $name ) {
@ -292,9 +285,9 @@ class EntityResolver {
public function getAttributeImplementing(string $interface) : ? object public function getAttributeImplementing(string $interface) : ? object
{ {
foreach (array_reverse($this->class['tags']) as $item) { foreach (array_reverse($this->reflectedClass->getAttributes(true)) as $item) {
if ($item['object'] instanceof $interface) { if ($item->object instanceof $interface) {
return $item['object']; return $item->object;
} }
} }
@ -303,61 +296,11 @@ class EntityResolver {
public function instanciateAnnotationObject(array|\ReflectionAttribute $tagDefinition) : object public function instanciateAnnotationObject(array|\ReflectionAttribute $tagDefinition) : object
{ {
if ($tagDefinition instanceof \ReflectionAttribute) { if ($tagDefinition instanceof \ReflectionAttribute) {
$obj = $tagDefinition->newInstance(); $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; 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);
}
}
}
} }

View File

@ -40,8 +40,10 @@ trait EntityTrait {
$entityResolver = $this->resolveEntity(); $entityResolver = $this->resolveEntity();
foreach($dataset as $key => $value) { foreach($dataset as $key => $value) {
$field = $entityResolver->field(strtolower($key), EntityResolver::KEY_COLUMN_NAME, false) ?? null; $field = $entityResolver->field(strtolower($key), EntityResolver::KEY_COLUMN_NAME, false) ?? $entityResolver->field(strtolower($key), EntityResolver::KEY_LC_ENTITY_NAME, false);
$field ??= $entityResolver->field(strtolower($key), EntityResolver::KEY_LC_ENTITY_NAME, false);
# Temp. fix, incoming patch soon
$type = $field->getTypes()[0];
if ( $field === null ) { if ( $field === null ) {
if ($this->entityStrictFieldsDeclaration ) { if ($this->entityStrictFieldsDeclaration ) {
@ -52,12 +54,12 @@ trait EntityTrait {
} }
} }
elseif ( is_null($value) ) { 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 ( is_string($value)) {
if (substr($value, 0, 1) === "a") { if (substr($value, 0, 1) === "a") {
$this->{$field['name']} = unserialize($value); $this->{$field->name} = unserialize($value);
} }
else { else {
$data = json_decode($value, true); $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)); 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) ) { 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' ) { if ( $type->type === 'string' ) {
$annotation = $entityResolver->searchFieldAnnotation($field['name'], [ Attribute\Property\Field::class, Field::class ] ); $annotation = $entityResolver->searchFieldAnnotation($field->name, [ Attribute\Property\Field::class ] );
if ( $annotation->length ?? null ) { if ( $annotation->length ?? null ) {
$value = mb_substr($value, 0, $annotation->length); $value = mb_substr($value, 0, $annotation->length);
} }
} }
elseif ( $field['type'] === 'bool' ) { elseif ( $type->type === 'bool' ) {
$value = (bool) $value; $value = (bool) $value;
} }
$this->{$field['name']} = $value; $this->{$field->name} = $value;
} }
elseif ( $value instanceof \UnitEnum ) { elseif ( $value instanceof \UnitEnum ) {
$this->{$field['name']} = $value; $this->{$field->name} = $value;
} }
elseif (enum_exists($field['type'])) { elseif (enum_exists($type->type)) {
$this->{$field['name']} = $field['type']::from($value); $this->{$field->name} = $type->type::from($value);
} }
elseif ( ! $field['builtin'] ) { elseif ( ! $type->builtIn ) {
try { try {
$this->{$field['name']} = Ulmus::instanciateObject($field['type'], [ $value ]); $this->{$field->name} = Ulmus::instanciateObject($type->type, [ $value ]);
} }
catch(\Error $e) { catch(\Error $e) {
$f = $field['type']; $f = $type->type;
throw new \Error(sprintf("%s for class '%s' on field '%s'", $e->getMessage(), get_class($this), $field['name'])); 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] #[Ignore]
public function resetVirtualProperties() : self public function resetVirtualProperties() : self
{ {
foreach($this->resolveEntity()->properties as $prop => $property) { foreach($this->resolveEntity()->reflectedClass->getProperties(true) as $prop => $property) {
foreach($property['tags'] as $tag) { foreach($property->attributes as $tag) {
if ( in_array(strtolower($tag['tag']), [ 'relation', 'join', 'virtual' ] ) ) { if ( in_array(strtolower($tag->tag), [ 'relation', 'join', 'virtual' ] ) ) {
unset($this->$prop); unset($this->$prop);
} }
} }
@ -155,7 +157,7 @@ trait EntityTrait {
$entityResolver = $this->resolveEntity(); $entityResolver = $this->resolveEntity();
foreach($entityResolver->fieldList(Common\EntityResolver::KEY_ENTITY_NAME, true) as $key => $field) { 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) ) { if ( isset($this->$key) ) {
$dataset[$annotation->name ?? $key] = $rewriteValue ? $dataset[$annotation->name ?? $key] = $rewriteValue ?
@ -163,13 +165,13 @@ trait EntityTrait {
: :
$this->$key; $this->$key;
} }
elseif ( $field['nullable'] ) { elseif ( $field->allowsNull() ) {
$dataset[$annotation->name ?? $key] = null; $dataset[$annotation->name ?? $key] = null;
} }
} }
if ($includeRelations) { if ($includeRelations) {
foreach($entityResolver->properties as $name => $field){ foreach($entityResolver->reflectedClass->getProperties(true) as $name => $field){
$relation = $entityResolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class ] ); $relation = $entityResolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class ] );
if ($relation) { if ($relation) {
@ -178,7 +180,7 @@ trait EntityTrait {
if ($ignore && $ignore->ignoreExport) { if ($ignore && $ignore->ignoreExport) {
if ( $relation->isOneToOne() ) { if ( $relation->isOneToOne() ) {
# empty object # empty object
$dataset[$name] = ( new \ReflectionClass($field['type']) )->newInstanceWithoutConstructor(); $dataset[$name] = ( new \ReflectionClass($field->getTypes()[0]) )->newInstanceWithoutConstructor();
} }
else { else {
# empty collection # empty collection
@ -326,7 +328,9 @@ trait EntityTrait {
{ {
$default = ( $alias === false ? '' : Repository::DEFAULT_ALIAS ); # bw compatibility, to be deprecated $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] #[Ignore]

View File

@ -2,6 +2,7 @@
namespace Ulmus\Migration; namespace Ulmus\Migration;
use Notes\Common\ReflectedProperty;
use Ulmus\Adapter\AdapterInterface; use Ulmus\Adapter\AdapterInterface;
use Ulmus\Annotation\Property\Field; use Ulmus\Annotation\Property\Field;
use Ulmus\Attribute; use Ulmus\Attribute;
@ -29,25 +30,28 @@ class FieldDefinition {
public AdapterInterface $adapter; public AdapterInterface $adapter;
public function __construct(AdapterInterface $adapter, array $data) public function __construct(AdapterInterface $adapter, ReflectedProperty $data)
{ {
$this->adapter = $adapter; $this->adapter = $adapter;
$this->name = $data['name']; # Patch coming soon
$this->builtIn = $data['builtin']; $type = $data->getTypes()[0];
$this->tags = $data['tags'];
if (isset($data['value'])) { $this->name = $data->name;
$this->default = $data['value']; $this->builtIn = $type->builtIn;
$this->tags = $data->getAttributes();
if (isset($data->value)) {
$this->default = $data->value;
} }
$field = $this->getFieldTag(); $field = $this->getFieldTag();
$adapter->whitelistAttributes($field->attributes); $adapter->whitelistAttributes($field->attributes);
$this->type = $field->type ?? $data['type']; $this->type = $field->type ?? $type->type;
$this->length = $field->length ?? null; $this->length = $field->length ?? null;
$this->precision = $field->precision ?? null; $this->precision = $field->precision ?? null;
$this->nullable = $data['nullable'] ?: $field->nullable; $this->nullable = $data->allowsNull() ?: $field->nullable;
$this->update = $field->attributes['update'] ?? null; $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 public function getColumnName() : ? string

View File

@ -133,8 +133,6 @@ class Repository
return $this->deleteFromPk($entity->$pkField); return $this->deleteFromPk($entity->$pkField);
} }
return false;
} }
public function destroyAll(EntityCollection $collection) : void public function destroyAll(EntityCollection $collection) : void
@ -397,8 +395,8 @@ class Repository
$prependField and ($prependField .= "$"); $prependField and ($prependField .= "$");
foreach ($entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) { 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 ])) {
$this->select(sprintf("%s.$key as {$prependField}{$field['name']}", $this->escapeIdentifier($alias))); $this->select(sprintf("%s.$key as {$prependField}{$field->name}", $this->escapeIdentifier($alias)));
} }
} }
@ -410,9 +408,9 @@ class Repository
$fieldlist = []; $fieldlist = [];
foreach ($entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) { 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[] = $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; $this->joined[$item] = true;
} }
$annotation = $this->entityResolver->searchFieldAnnotation($item, [ Attribute\Property\Join::class, Join::class ]) ?: $annotation = $this->entityResolver->searchFieldAnnotation($item, [ Attribute\Property\Join::class ]) ?:
$this->entityResolver->searchFieldAnnotation($item, [ Attribute\Property\Relation::class, Relation::class ]); $this->entityResolver->searchFieldAnnotation($item, [ Attribute\Property\Relation::class ]);
$isRelation = ( $annotation instanceof Relation ) || ($annotation instanceof Attribute\Property\Relation); $isRelation = ( $annotation instanceof Relation ) || ($annotation instanceof Attribute\Property\Relation);
if ($isRelation && ( $annotation->isManyToMany() )) { 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 ) { if ( $annotation ) {
$alias = $annotation->alias ?? $item; $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) { 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); $escAlias = $this->escapeIdentifier($alias);
$fieldName = $this->escapeIdentifier($key); $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}"); $this->select("$escAlias.$fieldName as $alias\${$name}");
@ -654,7 +652,7 @@ class Repository
$this->open(); $this->open();
if ( ! in_array(WithOptionEnum::SkipWhere, $options)) { 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 ) ) { 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); $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)) { 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); $this->having(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->getValue(), $condition->operator);
} }
} }
if ( ! in_array(WithOptionEnum::SkipFilter, $options)) { 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]); 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) { $this->join("LEFT", $entity::resolveEntity()->tableName(), $key, $foreignKey, $alias, function($join) use ($item, $entity, $alias, $options) {
if ( ! in_array(WithOptionEnum::SkipJoinWhere, $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) ) { if ( ! is_object($condition->field) ) {
$field = $this->entityClass::field($condition->field); $field = $this->entityClass::field($condition->field);
} }
@ -699,7 +697,7 @@ class Repository
} }
if ( ! in_array(WithOptionEnum::SkipJoinFilter, $options) ) { 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]); call_user_func_array([$this->entityClass, $filter->method], [$join, $item, true]);
} }
} }
@ -726,7 +724,7 @@ class Repository
# Apply FILTER annotation to this too ! # Apply FILTER annotation to this too !
foreach(array_filter((array) $fields) as $item) { 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; $alias = $relation->alias ?? $item;
if ( $relation->isManyToMany() ) { if ( $relation->isManyToMany() ) {
@ -747,11 +745,11 @@ class Repository
# $relation->isManyToMany() and $repository->selectJsonEntity($relation->bridge, $relation->bridgeField, true); # $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); $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); $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 public function loadCollectionRelation(EntityCollection $collection, array|string $fields) : void
{ {
foreach ((array)$fields as $name) { foreach ((array)$fields as $name) {
if (null !== ($relation = $this->entityResolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class, Relation::class ] ))) { if (null !== ($relation = $this->entityResolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class ] ))) {
$order = $this->entityResolver->searchFieldAnnotationList($name, [ Attribute\Property\OrderBy::class, OrderBy::class ]); $order = $this->entityResolver->searchFieldAnnotationList($name, [ Attribute\Property\OrderBy::class ]);
$where = $this->entityResolver->searchFieldAnnotationList($name, [ Attribute\Property\Where::class, Where::class ]); $where = $this->entityResolver->searchFieldAnnotationList($name, [ Attribute\Property\Where::class ]);
$baseEntity = $relation->entity ?? $relation->bridge ?? $this->entityResolver->properties[$name]['type']; $baseEntity = $relation->entity ?? $relation->bridge ?? $this->entityResolver->properties[$name]['type'];
$baseEntityResolver = $baseEntity::resolveEntity(); $baseEntityResolver = $baseEntity::resolveEntity();
@ -791,7 +789,7 @@ class Repository
$repository = $baseEntity::repository(); $repository = $baseEntity::repository();
foreach ($baseEntityResolver->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) { 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)); $repository->select($baseEntityResolver->entityClass::field($key));
} }
} }
@ -953,7 +951,7 @@ class Repository
{ {
if ( null === $this->queryBuilder->getFragment(Query\Select::class) ) { if ( null === $this->queryBuilder->getFragment(Query\Select::class) ) {
$fields = $this->entityResolver->fieldList(EntityResolver::KEY_COLUMN_NAME, true); $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) ) { if ( null === $this->queryBuilder->getFragment(Query\From::class) ) {

View File

@ -219,7 +219,7 @@ class RelationBuilder
$entity = $this->relationAnnotations($name, $annotation)['relationRelation']->entity; $entity = $this->relationAnnotations($name, $annotation)['relationRelation']->entity;
} }
else { else {
$entity = $annotation->entity ?? $this->resolver->properties[$name]['type']; $entity = $annotation->entity ?? $this->resolver->reflectedClass->getProperties()[$name]->getTypes()[0]->type;
} }
$name = strtolower($name); $name = strtolower($name);
@ -266,7 +266,7 @@ class RelationBuilder
public function oneToMany(string $name, Relation|Attribute\Property\Relation $relation) : Repository 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(); $this->repository = $baseEntity::repository();