spatie / laravel-activitylog

Log activity inside your Laravel app

Home Page:https://docs.spatie.be/laravel-activitylog

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Call to undefined method `getStorableEnumValue()`

GreenImp opened this issue · comments

Describe the bug
This bug is specific to Laravel 8 and v4.7.0 of this package.
When using Enums on model attributes, on a model which also uses the LogsActivity trait, an exception is thrown:

activity-log-exception

Call to undefined method `App\Models\Resrvation::getStorableEnumValue()

I've traced this back to this bit of code in the LogsActivity trait:

$changes[$attribute] = $model->getStorableEnumValue($changes[$attribute]);

Which was introduced in v4.7.0 in this PR: #1110

The problem being that the getStorableEnumValue() method was not introduced until Laravel 9:

https://github.com/laravel/framework/blob/571e02a39d0680c181e29bff835f17dfdc6cba34/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php#L1178-L1183

I'm assuming that a suitable fix would be to implement the code from that method inside the LogsActivity trait:

if (function_exists('enum_exists') && enum_exists($cast)) {
    if (method_exists($model, 'getStorableEnumValue')) {
        $changes[$attribute] = $model->getStorableEnumValue($changes[$attribute]);
    } else {
        $changes[$attribute] = $changes[$attribute] instanceof BackedEnum
            ? $changes[$attribute]->value
            : $changes[$attribute]->name;
    }
}

If you're happy with that, I can make a PR to fix it?

To Reproduce

  • Set up a project using Laravel 8.
  • Create a new model which has at least one attribute that uses an anum cast (I'm using backed enums, but I'm not sure it makes a difference), and uses the LogsActivity trait:
    class MyModel
    {
        use LogsActivity;
        
        protected $casts = [
            'an_enum' => AnEnum::class,
        ];
    
        public function getActivitylogOptions(): LogOptions
        {
            ...
        }
    }
  • Try to create or update an instance of the model
  • See the exception

Expected behavior
It shouldn't throw an exception.

Versions (please complete the following information)

  • PHP: 8
  • Database: mysql
  • Laravel: 8
  • Package: 4.7.0

Exception

Call to undefined method `App\Models\Resrvation::getStorableEnumValue()

Stack Trace

[2022-11-14 08:44:31] local.ERROR: Call to undefined method App\Models\Reservation::getStorableEnumValue() {"exception":"[object] (BadMethodCallException(code: 0): Call to undefined method App/Models/Reservation::getStorableEnumValue() at /var/www/html/vendor/laravel/framework/src/Illuminate/Support/Traits/ForwardsCalls.php:71)
[stacktrace]
#0 /var/www/html/vendor/laravel/framework/src/Illuminate/Support/Traits/ForwardsCalls.php(36): Illuminate/Database/Eloquent/Model::throwBadMethodCallException('getStorableEnum...')
#1 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(2132): Illuminate/Database/Eloquent/Model->forwardCallTo(Object(Illuminate/Database/Eloquent/Builder), 'getStorableEnum...', Array)
#2 /var/www/html/vendor/spatie/laravel-activitylog/src/Traits/LogsActivity.php(370): Illuminate/Database/Eloquent/Model->__call('getStorableEnum...', Array)
#3 /var/www/html/vendor/spatie/laravel-activitylog/src/Traits/LogsActivity.php(277): App/Models/Reservation::logChanges(Object(App/Models/Reservation))
#4 /var/www/html/vendor/spatie/laravel-activitylog/src/Traits/LogsActivity.php(54): App/Models/Reservation->attributeValuesToBeLogged('created')
#5 /var/www/html/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(404): App/Models/Reservation::Spatie/Activitylog/Traits/{closure}(Object(App/Models/Reservation))
#6 /var/www/html/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(249): Illuminate/Events/Dispatcher->Illuminate/Events/{closure}('eloquent.create...', Array)
#7 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasEvents.php(189): Illuminate/Events/Dispatcher->dispatch('eloquent.create...', Array)
#8 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1174): Illuminate/Database/Eloquent/Model->fireModelEvent('created', false)
#9 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(994): Illuminate/Database/Eloquent/Model->performInsert(Object(Illuminate/Database/Eloquent/Builder))
#10 /var/www/html/app/Services/Reservation/ReservationService.php(116): Illuminate/Database/Eloquent/Model->save()
#11 /var/www/html/app/Services/Reservation/ReservationService.php(354): App/Services/Reservation/ReservationService->create()
#12 /var/www/html/app/Services/Reservation/ReservationService.php(338): App/Services/Reservation/ReservationService->createSession()
#13 /var/www/html/app/Http/Requests/Reservations/ShowSearch.php(15): App/Services/Reservation/ReservationService->getSession()
#14 /var/www/html/routes/app.php(76): App/Http/Requests/Reservations/ShowSearch->process()
#15 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Route.php(238): Illuminate/Routing/RouteFileRegistrar->{closure}(Object(App/Http/Requests/Reservations/ShowSearch))
#16 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Route.php(208): Illuminate/Routing/Route->runCallable()
#17 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(721): Illuminate/Routing/Route->run()
#18 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(128): Illuminate/Routing/Router->Illuminate/Routing/{closure}(Object(Illuminate/Http/Request))
#19 /var/www/html/vendor/inertiajs/inertia-laravel/src/Middleware.php(88): Illuminate/Pipeline/Pipeline->Illuminate/Pipeline/{closure}(Object(Illuminate/Http/Request))
#20 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Inertia/Middleware->handle(Object(Illuminate/Http/Request), Object(Closure))
#21 /var/www/html/app/Http/Middleware/RequestLogging.php(29): Illuminate/Pipeline/Pipeline->Illuminate/Pipeline/{closure}(Object(Illuminate/Http/Request))
#22 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): App/Http/Middleware/RequestLogging->handle(Object(Illuminate/Http/Request), Object(Closure))
#23 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php(50): Illuminate/Pipeline/Pipeline->Illuminate/Pipeline/{closure}(Object(Illuminate/Http/Request))
#24 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate/Routing/Middleware/SubstituteBindings->handle(Object(Illuminate/Http/Request), Object(Closure))
#25 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php(78): Illuminate/Pipeline/Pipeline->Illuminate/Pipeline/{closure}(Object(Illuminate/Http/Request))
#26 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate/Foundation/Http/Middleware/VerifyCsrfToken->handle(Object(Illuminate/Http/Request), Object(Closure))
#27 /var/www/html/vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php(49): Illuminate/Pipeline/Pipeline->Illuminate/Pipeline/{closure}(Object(Illuminate/Http/Request))
#28 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate/View/Middleware/ShareErrorsFromSession->handle(Object(Illuminate/Http/Request), Object(Closure))
#29 /var/www/html/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(121): Illuminate/Pipeline/Pipeline->Illuminate/Pipeline/{closure}(Object(Illuminate/Http/Request))
#30 /var/www/html/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(64): Illuminate/Session/Middleware/StartSession->handleStatefulRequest(Object(Illuminate/Http/Request), Object(Illuminate/Session/Store), Object(Closure))
#31 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate/Session/Middleware/StartSession->handle(Object(Illuminate/Http/Request), Object(Closure))
#32 /var/www/html/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php(37): Illuminate/Pipeline/Pipeline->Illuminate/Pipeline/{closure}(Object(Illuminate/Http/Request))
#33 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse->handle(Object(Illuminate/Http/Request), Object(Closure))
#34 /var/www/html/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php(67): Illuminate/Pipeline/Pipeline->Illuminate/Pipeline/{closure}(Object(Illuminate/Http/Request))
#35 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate/Cookie/Middleware/EncryptCookies->handle(Object(Illuminate/Http/Request), Object(Closure))
#36 /var/www/html/app/Http/Middleware/System.php(25): Illuminate/Pipeline/Pipeline->Illuminate/Pipeline/{closure}(Object(Illuminate/Http/Request))
#37 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): App/Http/Middleware/System->handle(Object(Illuminate/Http/Request), Object(Closure))
#38 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(103): Illuminate/Pipeline/Pipeline->Illuminate/Pipeline/{closure}(Object(Illuminate/Http/Request))
#39 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(723): Illuminate/Pipeline/Pipeline->then(Object(Closure))
#40 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(698): Illuminate/Routing/Router->runRouteWithinStack(Object(Illuminate/Routing/Route), Object(Illuminate/Http/Request))
#41 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(662): Illuminate/Routing/Router->runRoute(Object(Illuminate/Http/Request), Object(Illuminate/Routing/Route))
#42 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(651): Illuminate/Routing/Router->dispatchToRoute(Object(Illuminate/Http/Request))
#43 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(167): Illuminate/Routing/Router->dispatch(Object(Illuminate/Http/Request))
#44 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(128): Illuminate/Foundation/Http/Kernel->Illuminate/Foundation/Http/{closure}(Object(Illuminate/Http/Request))
#45 /var/www/html/vendor/laravel/vapor-core/src/Http/Middleware/ServeStaticAssets.php(21): Illuminate/Pipeline/Pipeline->Illuminate/Pipeline/{closure}(Object(Illuminate/Http/Request))
#46 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Laravel/Vapor/Http/Middleware/ServeStaticAssets->handle(Object(Illuminate/Http/Request), Object(Closure))
#47 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate/Pipeline/Pipeline->Illuminate/Pipeline/{closure}(Object(Illuminate/Http/Request))
#48 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull.php(31): Illuminate/Foundation/Http/Middleware/TransformsRequest->handle(Object(Illuminate/Http/Request), Object(Closure))
#49 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull->handle(Object(Illuminate/Http/Request), Object(Closure))
#50 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate/Pipeline/Pipeline->Illuminate/Pipeline/{closure}(Object(Illuminate/Http/Request))
#51 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php(40): Illuminate/Foundation/Http/Middleware/TransformsRequest->handle(Object(Illuminate/Http/Request), Object(Closure))
#52 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate/Foundation/Http/Middleware/TrimStrings->handle(Object(Illuminate/Http/Request), Object(Closure))
#53 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php(27): Illuminate/Pipeline/Pipeline->Illuminate/Pipeline/{closure}(Object(Illuminate/Http/Request))
#54 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate/Foundation/Http/Middleware/ValidatePostSize->handle(Object(Illuminate/Http/Request), Object(Closure))
#55 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php(86): Illuminate/Pipeline/Pipeline->Illuminate/Pipeline/{closure}(Object(Illuminate/Http/Request))
#56 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance->handle(Object(Illuminate/Http/Request), Object(Closure))
#57 /var/www/html/vendor/fruitcake/laravel-cors/src/HandleCors.php(38): Illuminate/Pipeline/Pipeline->Illuminate/Pipeline/{closure}(Object(Illuminate/Http/Request))
#58 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Fruitcake/Cors/HandleCors->handle(Object(Illuminate/Http/Request), Object(Closure))
#59 /var/www/html/vendor/laravel/framework/src/Illuminate/Http/Middleware/TrustProxies.php(39): Illuminate/Pipeline/Pipeline->Illuminate/Pipeline/{closure}(Object(Illuminate/Http/Request))
#60 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate/Http/Middleware/TrustProxies->handle(Object(Illuminate/Http/Request), Object(Closure))
#61 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(103): Illuminate/Pipeline/Pipeline->Illuminate/Pipeline/{closure}(Object(Illuminate/Http/Request))
#62 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(142): Illuminate/Pipeline/Pipeline->then(Object(Closure))
#63 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(111): Illuminate/Foundation/Http/Kernel->sendRequestThroughRouter(Object(Illuminate/Http/Request))
#64 /var/www/html/public/index.php(52): Illuminate/Foundation/Http/Kernel->handle(Object(Illuminate/Http/Request))
#65 {main}
"}

Thanks for your full report - I'm on that now and will come up with a full fix for the whole test matrix.
Sorry for the bug(s). 🙏

Fantastic, thank you!

I've tried to solve it for everything - could you test it?
#1121

Yeah, that seems to work for me!

@Gummibeer
The error resurfaced in v4.8.0
#1301