diff --git a/src/Annotation/Property/Virtual.php b/src/Annotation/Property/Virtual.php index 295c938..cf947f2 100644 --- a/src/Annotation/Property/Virtual.php +++ b/src/Annotation/Property/Virtual.php @@ -3,7 +3,17 @@ namespace Ulmus\Annotation\Property; class Virtual extends Field { - public Closure $closure; public bool $readonly = true; + + public \Closure $closure; + + public string $method; + + public function __construct(? \Closure $closure = null) + { + if ( $closure !== null ) { + $this->closure = $closure; + } + } } diff --git a/src/EntityTrait.php b/src/EntityTrait.php index f5640a0..d851fb6 100644 --- a/src/EntityTrait.php +++ b/src/EntityTrait.php @@ -9,7 +9,7 @@ use Ulmus\Repository, use Ulmus\Annotation\Classes\{ Method, Table, Collation, }; use Ulmus\Annotation\Property\{ Field, Filter, FilterJoin, Relation, OrderBy, Where, OrWhere, Join, Virtual, On, WithJoin, }; -use Ulmus\Annotation\Property\Field\{ Id, ForeignKey, CreatedAt, UpdatedAt, Datetime as DateTime, Date, Time, Bigint, Tinyint, Blob, Text, Mediumtext, Longtext, Tinyblob, Mediumblob, Longblob }; +use Ulmus\Annotation\Property\Field\{ Id, ForeignKey, CreatedAt, UpdatedAt, Datetime as DateTime, Date, Time, Bigint, Tinyint, Text, Mediumtext, Longtext, }; use Ulmus\Annotation\Property\Relation\{ Ignore as RelationIgnore }; trait EntityTrait { @@ -30,6 +30,10 @@ trait EntityTrait { */ public array $entityLoadedDataset = []; + public function __construct() { + $this->resetVirtualProperties(); + } + /**entityLoadedDataset * @Ignore */ @@ -108,7 +112,7 @@ trait EntityTrait { foreach($this->resolveEntity()->properties as $prop => $property) { if ( ! $property['builtin'] ) { foreach($property['tags'] as $tag) { - if ( in_array(strtolower($tag['tag']), [ 'relation', 'join' ] ) ) { + if ( in_array(strtolower($tag['tag']), [ 'relation', 'join', 'virtual' ] ) ) { unset($this->$prop); } } diff --git a/src/Repository/RelationBuilder.php b/src/Repository/RelationBuilder.php index 8024250..d95f8e7 100644 --- a/src/Repository/RelationBuilder.php +++ b/src/Repository/RelationBuilder.php @@ -45,11 +45,27 @@ class RelationBuilder return $dataset; } - return $this->resolveRelation($name); + return $this->resolveRelation($name) ?: $this->resolveVirtual($name); + } + else { + return $this->instanciateEmptyObject($name, $this->resolver->searchFieldAnnotation($name, new Relation() )); } } - protected function resolveRelation(string $name) /* : object|EntityCollection */ + protected function resolveVirtual(string $name) /* : bool|object|EntityCollection */ + { + if (null !== ($virtual = $this->resolver->searchFieldAnnotation($name, new Annotation\Property\Virtual()))) { + if ($virtual->closure ?? false) { + return call_user_func_array($virtual->closure, [ $this->entity ]); + } + + return call_user_func_array([ $this->entity, $virtual->method ], [ $this->entity ]); + } + + return false; + } + + protected function resolveRelation(string $name) /* : bool|object|EntityCollection */ { if ( null !== ( $relation = $this->resolver->searchFieldAnnotation($name, new Relation() ) ) ) { $this->orders = $this->resolver->searchFieldAnnotationList($name, new OrderBy() ); @@ -139,6 +155,25 @@ class RelationBuilder return new $class(); } + + protected function instanciateEmptyObject(string $name, Relation $relation) : object + { + switch( true ) { + case $relation->isOneToOne(): + return $this->instanciateEmptyEntity($name, $relation); + + case $relation->isOneToMany(): + return ($relation->entity ?? $this->resolver->properties[$name]['type'])::entityCollection(); + + case $relation->isManyToMany(): + extract($this->relationAnnotations($name, $relation)); + + return $relation->bridgeField ?? false ? $relation->bridge::entityCollection() : $relationRelation->entity::entityCollection(); + } + + return new $class(); + } + protected function fetchFromDataset($name, ? array $data = null) /* object|bool */ { $annotation = $this->resolver->searchFieldAnnotation($name, new Annotation\Property\Join) ?: