From 4bd6a37ce6e475a365f89f761b94462b846f6cd7 Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Fri, 1 Aug 2025 13:41:02 -0600 Subject: [PATCH 1/5] Update existing bootTraits implementation --- .../Database/Eloquent/Attributes/Boot.php | 11 ++++++ .../Eloquent/Attributes/Initialize.php | 11 ++++++ src/Illuminate/Database/Eloquent/Model.php | 38 ++++++++++++------- 3 files changed, 47 insertions(+), 13 deletions(-) create mode 100644 src/Illuminate/Database/Eloquent/Attributes/Boot.php create mode 100644 src/Illuminate/Database/Eloquent/Attributes/Initialize.php diff --git a/src/Illuminate/Database/Eloquent/Attributes/Boot.php b/src/Illuminate/Database/Eloquent/Attributes/Boot.php new file mode 100644 index 000000000000..f57da7af9450 --- /dev/null +++ b/src/Illuminate/Database/Eloquent/Attributes/Boot.php @@ -0,0 +1,11 @@ + 'boot'.class_basename($trait), $uses); + $conventionalInitMethods = array_map(static fn ($trait) => 'initialize'.class_basename($trait), $uses); + + foreach ((new ReflectionClass($class))->getMethods() as $method) { + if ( + ! in_array($method->getName(), $booted) && + $method->isStatic() && + ( + in_array($method->getName(), $conventionalBootMethods) || + $method->getAttributes(Boot::class) !== [] + ) + ) { + $method->invoke(null); + $booted[] = $method->getName(); } - if (method_exists($class, $method = 'initialize'.class_basename($trait))) { - static::$traitInitializers[$class][] = $method; - - static::$traitInitializers[$class] = array_unique( - static::$traitInitializers[$class] - ); + if ( + in_array($method->getName(), $conventionalInitMethods) || + $method->getAttributes(Initialize::class) !== [] + ) { + static::$traitInitializers[$class][] = $method->getName(); } } + + static::$traitInitializers[$class] = array_unique(static::$traitInitializers[$class]); } /** From c0bda0d1fafd53a3437ad5463c9a3bf532545b6d Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Fri, 1 Aug 2025 13:41:21 -0600 Subject: [PATCH 2/5] Add tests --- .../Queue/ModelSerializationTest.php | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tests/Integration/Queue/ModelSerializationTest.php b/tests/Integration/Queue/ModelSerializationTest.php index e13cbb4ec293..5fc6557740c8 100644 --- a/tests/Integration/Queue/ModelSerializationTest.php +++ b/tests/Integration/Queue/ModelSerializationTest.php @@ -2,6 +2,8 @@ namespace Illuminate\Tests\Integration\Queue; +use Illuminate\Database\Eloquent\Attributes\Boot; +use Illuminate\Database\Eloquent\Attributes\Initialize; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\Pivot; @@ -210,16 +212,26 @@ public function testItCanRunModelBootsAndTraitInitializations() $model = new ModelBootTestWithTraitInitialization(); $this->assertTrue($model->fooBar); + $this->assertTrue($model->initializedViaAttributeInClass); + $this->assertTrue($model->initializedViaAttributeInTrait); $this->assertTrue($model::hasGlobalScope('foo_bar')); + $this->assertTrue($model::hasGlobalScope('booted_attr_in_class')); + $this->assertTrue($model::hasGlobalScope('booted_attr_in_trait')); $model::clearBootedModels(); $this->assertFalse($model::hasGlobalScope('foo_bar')); + $this->assertFalse($model::hasGlobalScope('booted_attr_in_class')); + $this->assertFalse($model::hasGlobalScope('booted_attr_in_trait')); $unSerializedModel = unserialize(serialize($model)); $this->assertFalse($unSerializedModel->fooBar); + $this->assertFalse($unSerializedModel->initializedViaAttributeInClass); + $this->assertFalse($unSerializedModel->initializedViaAttributeInTrait); $this->assertTrue($model::hasGlobalScope('foo_bar')); + $this->assertTrue($model::hasGlobalScope('booted_attr_in_class')); + $this->assertTrue($model::hasGlobalScope('booted_attr_in_trait')); } /** @@ -402,6 +414,8 @@ public function test_serialization_types_empty_custom_eloquent_collection() trait TraitBootsAndInitializersTest { + public bool $initializedViaAttributeInTrait = false; + public $fooBar = false; public function initializeTraitBootsAndInitializersTest() @@ -414,11 +428,39 @@ public static function bootTraitBootsAndInitializersTest() static::addGlobalScope('foo_bar', function () { }); } + + #[Boot] + public static function nonConventionalBootFunctionInTrait() + { + static::addGlobalScope('booted_attr_in_trait', function () {}); + } + + #[Initialize] + public function nonConventionalInitFunctionInTrait() + { + $this->initializedViaAttributeInTrait = ! $this->initializedViaAttributeInTrait; + } } class ModelBootTestWithTraitInitialization extends Model { use TraitBootsAndInitializersTest; + + public static bool $bootedViaAttributeInClass = false; + + public bool $initializedViaAttributeInClass = false; + + #[Boot] + public static function nonConventionalBootFunctionInClass() + { + static::addGlobalScope('booted_attr_in_class', function () {}); + } + + #[Initialize] + public function nonConventionalInitFunctionInClass() + { + $this->initializedViaAttributeInClass = ! $this->initializedViaAttributeInClass; + } } class ModelSerializationTestUser extends Model From 868800358b35d668e2e42ad5069b901185f3823a Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Fri, 1 Aug 2025 13:42:46 -0600 Subject: [PATCH 3/5] Remove WeakMap --- src/Illuminate/Database/Eloquent/Model.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 6dc3d0372fa0..28be14713754 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -32,7 +32,6 @@ use ReflectionClass; use ReflectionMethod; use Stringable; -use WeakMap; abstract class Model implements Arrayable, ArrayAccess, CanBeEscapedWhenCastToString, HasBroadcastChannel, Jsonable, JsonSerializable, QueueableEntity, Stringable, UrlRoutable { From 1fcc68c7116d6fdde93afe5504f0bb924e4c3143 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 3 Aug 2025 09:22:17 -0500 Subject: [PATCH 4/5] formatting --- src/Illuminate/Database/Eloquent/Model.php | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 28be14713754..7fee6bfab537 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -363,26 +363,22 @@ protected static function bootTraits() static::$traitInitializers[$class] = []; $uses = class_uses_recursive($class); + $conventionalBootMethods = array_map(static fn ($trait) => 'boot'.class_basename($trait), $uses); $conventionalInitMethods = array_map(static fn ($trait) => 'initialize'.class_basename($trait), $uses); foreach ((new ReflectionClass($class))->getMethods() as $method) { - if ( - ! in_array($method->getName(), $booted) && + if (! in_array($method->getName(), $booted) && $method->isStatic() && - ( - in_array($method->getName(), $conventionalBootMethods) || - $method->getAttributes(Boot::class) !== [] - ) - ) { + (in_array($method->getName(), $conventionalBootMethods) || + $method->getAttributes(Boot::class) !== [])) { $method->invoke(null); + $booted[] = $method->getName(); } - if ( - in_array($method->getName(), $conventionalInitMethods) || - $method->getAttributes(Initialize::class) !== [] - ) { + if (in_array($method->getName(), $conventionalInitMethods) || + $method->getAttributes(Initialize::class) !== []) { static::$traitInitializers[$class][] = $method->getName(); } } From 9e589b28409034c62dd653746d0982c4441e5c8b Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 3 Aug 2025 09:23:36 -0500 Subject: [PATCH 5/5] formatting --- src/Illuminate/Database/Eloquent/Model.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 7fee6bfab537..94973c365318 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -371,7 +371,7 @@ protected static function bootTraits() if (! in_array($method->getName(), $booted) && $method->isStatic() && (in_array($method->getName(), $conventionalBootMethods) || - $method->getAttributes(Boot::class) !== [])) { + $method->getAttributes(Boot::class) !== [])) { $method->invoke(null); $booted[] = $method->getName();