Skip to content

Commit

Permalink
Support ObservedBy on parent model classes (#53579)
Browse files Browse the repository at this point in the history
* Support ObservedBy on parent model classes

* Traverse entire ancestry

* Prepend parent observers instead of append

* add test

* remove unused includes
  • Loading branch information
adamthehutt authored Nov 19, 2024
1 parent 3c672db commit 11508cd
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 0 deletions.
9 changes: 9 additions & 0 deletions src/Illuminate/Database/Eloquent/Concerns/HasEvents.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Events\NullDispatcher;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use InvalidArgumentException;
use ReflectionClass;

Expand Down Expand Up @@ -48,9 +50,16 @@ public static function resolveObserveAttributes()
{
$reflectionClass = new ReflectionClass(static::class);

$isEloquentGrandchild = is_subclass_of(static::class, Model::class)
&& get_parent_class(static::class) !== Model::class;

return collect($reflectionClass->getAttributes(ObservedBy::class))
->map(fn ($attribute) => $attribute->getArguments())
->flatten()
->when($isEloquentGrandchild, function (Collection $attributes) {
return collect(get_parent_class(static::class)::resolveObserveAttributes())
->merge($attributes);
})
->all();
}

Expand Down
45 changes: 45 additions & 0 deletions tests/Database/DatabaseEloquentModelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2106,6 +2106,20 @@ public function testModelObserversCanBeAttachedToModelsThroughAnArrayUsingAttrib
EloquentModelWithObserveAttributeUsingArrayStub::flushEventListeners();
}

public function testModelObserversCanBeAttachedToModelsThroughAttributesOnParentClasses()
{
EloquentModelWithObserveAttributeGrandchildStub::setEventDispatcher($events = m::mock(Dispatcher::class));
$events->shouldReceive('dispatch');
$events->shouldReceive('listen')->once()->with('eloquent.creating: Illuminate\Tests\Database\EloquentModelWithObserveAttributeGrandchildStub', EloquentTestObserverStub::class.'@creating');
$events->shouldReceive('listen')->once()->with('eloquent.saved: Illuminate\Tests\Database\EloquentModelWithObserveAttributeGrandchildStub', EloquentTestObserverStub::class.'@saved');
$events->shouldReceive('listen')->once()->with('eloquent.creating: Illuminate\Tests\Database\EloquentModelWithObserveAttributeGrandchildStub', EloquentTestAnotherObserverStub::class.'@creating');
$events->shouldReceive('listen')->once()->with('eloquent.saved: Illuminate\Tests\Database\EloquentModelWithObserveAttributeGrandchildStub', EloquentTestAnotherObserverStub::class.'@saved');
$events->shouldReceive('listen')->once()->with('eloquent.creating: Illuminate\Tests\Database\EloquentModelWithObserveAttributeGrandchildStub', EloquentTestThirdObserverStub::class.'@creating');
$events->shouldReceive('listen')->once()->with('eloquent.saved: Illuminate\Tests\Database\EloquentModelWithObserveAttributeGrandchildStub', EloquentTestThirdObserverStub::class.'@saved');
$events->shouldReceive('forget');
EloquentModelWithObserveAttributeGrandchildStub::flushEventListeners();
}

public function testThrowExceptionOnAttachingNotExistsModelObserverWithString()
{
$this->expectException(InvalidArgumentException::class);
Expand Down Expand Up @@ -3206,6 +3220,19 @@ public function saved()
}
}

class EloquentTestThirdObserverStub
{
public function creating()
{
//
}

public function saved()
{
//
}
}

class EloquentModelStub extends Model
{
public $connection;
Expand Down Expand Up @@ -3699,6 +3726,24 @@ class EloquentModelWithObserveAttributeUsingArrayStub extends EloquentModelStub
//
}

#[ObservedBy([EloquentTestObserverStub::class])]
class EloquentModelWithObserveAttributeGrandparentStub extends EloquentModelStub
{
//
}

#[ObservedBy([EloquentTestAnotherObserverStub::class])]
class EloquentModelWithObserveAttributeParentStub extends EloquentModelWithObserveAttributeGrandparentStub
{
//
}

#[ObservedBy([EloquentTestThirdObserverStub::class])]
class EloquentModelWithObserveAttributeGrandchildStub extends EloquentModelWithObserveAttributeParentStub
{
//
}

class EloquentModelSavingEventStub
{
//
Expand Down

0 comments on commit 11508cd

Please sign in to comment.