diff --git a/src/Attribute/Property/Virtual.php b/src/Attribute/Property/Virtual.php index 64f5874..ae53107 100644 --- a/src/Attribute/Property/Virtual.php +++ b/src/Attribute/Property/Virtual.php @@ -8,6 +8,14 @@ class Virtual extends Field { public bool $readonly = true; public function __construct( - public ? string $method = null, - ) {} + public null|string|array $method = null, + public ? \Closure $closure = null, + ) { + $this->method ??= [ static::class, 'noop' ]; + } + + public static function noop() : null + { + return null; + } } diff --git a/src/Repository/RelationBuilder.php b/src/Repository/RelationBuilder.php index 796da0d..498d2e0 100644 --- a/src/Repository/RelationBuilder.php +++ b/src/Repository/RelationBuilder.php @@ -56,10 +56,10 @@ class RelationBuilder } if ( false !== $value = $this->resolveRelation($name) ) { - return $value; + return $value; } - elseif ( false !== $value = $this->resolveVirtual($name) ) { - return $value; + elseif ( false !== $value = $this->resolveVirtual($name) ) { + return $value; } } @@ -78,11 +78,19 @@ class RelationBuilder protected function resolveVirtual(string $name) : mixed { if (null !== ($virtual = $this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Virtual::class, Annotation\Property\Virtual::class ]))) { - if ($virtual->closure ?? false) { - return call_user_func_array($virtual->closure, [ $this->entity ]); - } + try { + $arguments = [ $this->entity ]; - return call_user_func_array([ $this->entity, $virtual->method ], [ $this->entity ]); + if ($virtual->closure ?? false) { + return call_user_func_array($virtual->closure, $arguments); + } + elseif ($virtual->method ?? false) { + return call_user_func_array(is_array($virtual->method) ? $virtual->method : [$this->entity, $virtual->method], $arguments); + } + } + catch(\Throwable $e) { + throw new $e(sprintf("An error occurred while calling method from your #[Virtual] attribute in entity '%s::%s'.", $this->entity::class, $name )); + } } return false; @@ -115,7 +123,7 @@ class RelationBuilder $this->entity->eventExecute(Event\EntityRelationLoadInterface::class, $name, $this->repository); -return call_user_func([ $this->repository, $relation->function() ]); + return call_user_func([ $this->repository, $relation->function() ]); case $relation->isManyToMany(): $this->manyToMany($name, $relation, $relationRelation);