Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions src/core/src/Database/Eloquent/Attributes/ObservedBy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace Hypervel\Database\Eloquent\Attributes;

use Attribute;

/**
* Declare observers for a model using an attribute.
*
* When placed on a model class, the specified observer(s) will be automatically
* registered when the model boots. Attributes on parent classes are inherited
* by child classes.
*
* @example
* ```php
* #[ObservedBy(UserObserver::class)]
* class User extends Model {}
*
* #[ObservedBy([AuditObserver::class, CacheObserver::class])]
* class Post extends Model {}
* ```
*/
#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
class ObservedBy
{
/**
* Create a new attribute instance.
*
* @param class-string|class-string[] $classes
*/
public function __construct(
public array|string $classes
) {
}
}
65 changes: 65 additions & 0 deletions src/core/src/Database/Eloquent/Concerns/HasObservers.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,77 @@
namespace Hypervel\Database\Eloquent\Concerns;

use Hyperf\Collection\Arr;
use Hyperf\Collection\Collection;
use Hyperf\Database\Model\Model as HyperfModel;
use Hypervel\Context\ApplicationContext;
use Hypervel\Database\Eloquent\Attributes\ObservedBy;
use Hypervel\Database\Eloquent\ObserverManager;
use ReflectionAttribute;
use ReflectionClass;
use RuntimeException;

trait HasObservers
{
/**
* Boot the has observers trait for a model.
*
* Automatically registers any observers declared via the ObservedBy attribute.
*/
public static function bootHasObservers(): void
{
$observers = static::resolveObserveAttributes();

if (! empty($observers)) {
static::observe($observers);
}
}

/**
* Resolve the observer class names from the ObservedBy attributes.
*
* Collects ObservedBy attributes from parent classes, traits, and the
* current class itself, merging them together. The order is:
* parent class observers -> trait observers -> class observers.
*
* @return array<int, class-string>
*/
public static function resolveObserveAttributes(): array
{
$reflectionClass = new ReflectionClass(static::class);

$parentClass = get_parent_class(static::class);
$hasParentWithTrait = $parentClass
&& $parentClass !== HyperfModel::class
&& method_exists($parentClass, 'resolveObserveAttributes');

// Collect attributes from traits, then from the class itself
$attributes = new Collection();

foreach ($reflectionClass->getTraits() as $trait) {
foreach ($trait->getAttributes(ObservedBy::class, ReflectionAttribute::IS_INSTANCEOF) as $attribute) {
$attributes->push($attribute);
}
}

foreach ($reflectionClass->getAttributes(ObservedBy::class, ReflectionAttribute::IS_INSTANCEOF) as $attribute) {
$attributes->push($attribute);
}

// Process all collected attributes
$observers = $attributes
->map(fn (ReflectionAttribute $attribute) => $attribute->getArguments())
->flatten();

// Prepend parent's observers if applicable
return $observers
->when($hasParentWithTrait, function (Collection $attrs) use ($parentClass) {
/** @var class-string $parentClass */
return (new Collection($parentClass::resolveObserveAttributes()))
->merge($attrs);
})
->all();
}

/**
* Register observers with the model.
*
Expand Down
2 changes: 2 additions & 0 deletions src/core/src/Database/Eloquent/Relations/MorphPivot.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
namespace Hypervel\Database\Eloquent\Relations;

use Hyperf\Database\Model\Relations\MorphPivot as BaseMorphPivot;
use Hypervel\Database\Eloquent\Concerns\HasObservers;

class MorphPivot extends BaseMorphPivot
{
use HasObservers;
}
2 changes: 2 additions & 0 deletions src/core/src/Database/Eloquent/Relations/Pivot.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
namespace Hypervel\Database\Eloquent\Relations;

use Hyperf\Database\Model\Relations\Pivot as BasePivot;
use Hypervel\Database\Eloquent\Concerns\HasObservers;

class Pivot extends BasePivot
{
use HasObservers;
}
Loading