4242use ReflectionNamedType ;
4343use RuntimeException ;
4444use Stringable ;
45+ use Throwable ;
4546use ValueError ;
4647
4748use function Illuminate \Support \enum_value ;
@@ -221,8 +222,11 @@ public function attributesToArray()
221222 $ attributes = $ this ->getArrayableAttributes ()
222223 );
223224
224- // Important: derive mutated attributes *only* from the arrayable keys
225- $ mutatedAttributes = $ this ->getArrayableMutatedAttributes ($ attributes );
225+ $ mutatedAttributes = array_values (
226+ array_filter (array_keys ($ attributes ), function ($ key ) {
227+ return $ this ->hasAnyGetMutator ($ key );
228+ })
229+ );
226230
227231 $ attributes = $ this ->addMutatedAttributesToArray (
228232 $ attributes , $ mutatedAttributes
@@ -688,17 +692,15 @@ public function hasAttributeGetMutator($key)
688692 return static ::$ getAttributeMutatorCache [$ class ][$ key ];
689693 }
690694
691- // First, ensure there's actually an Attribute-returning method
692695 if (! $ this ->hasAttributeMutator ($ key )) {
693696 return static ::$ getAttributeMutatorCache [$ class ][$ key ] = false ;
694697 }
695698
696- // Lazy evaluation: only now do we resolve and inspect the Attribute
697699 try {
698700 $ attribute = $ this ->{Str::camel ($ key )}();
699701
700702 return static ::$ getAttributeMutatorCache [$ class ][$ key ] = is_callable ($ attribute ->get );
701- } catch (\ Throwable $ e ) {
703+ } catch (Throwable $ e ) {
702704 return static ::$ getAttributeMutatorCache [$ class ][$ key ] = false ;
703705 }
704706 }
@@ -766,7 +768,6 @@ protected function mutateAttributeForArray($key, $value)
766768 if ($ this ->isClassCastable ($ key )) {
767769 $ value = $ this ->getClassCastableAttributeValue ($ key , $ value );
768770 } elseif ($ this ->hasAttributeGetMutator ($ key )) {
769- // Attribute::make(get: ...)
770771 $ value = $ this ->mutateAttributeMarkedAttribute ($ key , $ value );
771772
772773 if ($ value instanceof DateTimeInterface) {
@@ -2450,20 +2451,6 @@ public function getMutatedAttributes()
24502451 return static ::$ mutatorCache [static ::class];
24512452 }
24522453
2453- protected function getArrayableMutatedAttributes (array $ attributes ): array
2454- {
2455- $ keys = array_keys ($ attributes );
2456-
2457- if ($ keys === []) {
2458- return [];
2459- }
2460-
2461- // Only consider keys that are actually arrayable *and* have a mutator
2462- return array_values (array_filter ($ keys , function ($ key ) {
2463- return $ this ->hasAnyGetMutator ($ key );
2464- }));
2465- }
2466-
24672454 /**
24682455 * Extract and cache all the mutated attributes of a class.
24692456 *
@@ -2476,13 +2463,8 @@ public static function cacheMutatedAttributes($classOrInstance)
24762463
24772464 $ class = $ reflection ->getName ();
24782465
2479- // Get Attribute return type methods without invoking them (lazy caching)
24802466 $ attributeMutatorMethods = static ::getAttributeMarkedMutatorMethods ($ classOrInstance );
24812467
2482- // Initialize cache with method names but don't set to true yet
2483- // This allows us to know which methods might be Attribute mutators
2484- // without invoking them. The actual 'get' callable check happens lazily
2485- // in hasAttributeGetMutator() when the attribute is actually accessed.
24862468 static ::$ getAttributeMutatorCache [$ class ] = (new Collection ($ attributeMutatorMethods ))
24872469 ->mapWithKeys (fn ($ match ) => [
24882470 lcfirst (static ::$ snakeAttributes ? Str::snake ($ match ) : $ match ) => null ,
@@ -2519,8 +2501,12 @@ protected static function getAttributeMarkedMutatorMethods($class)
25192501 $ instance = is_object ($ class ) ? $ class : new $ class ;
25202502
25212503 return (new Collection ((new ReflectionClass ($ instance ))->getMethods ()))
2522- ->filter (fn ($ method ) => $ method ->getReturnType () instanceof ReflectionNamedType &&
2523- $ method ->getReturnType ()->getName () === Attribute::class)
2524- ->map ->name ->values ()->all ();
2504+ ->filter (
2505+ fn ($ method ) => $ method ->getReturnType () instanceof ReflectionNamedType &&
2506+ $ method ->getReturnType ()->getName () === Attribute::class)
2507+ ->map
2508+ ->name
2509+ ->values ()
2510+ ->all ();
25252511 }
25262512}
0 commit comments