laravel/nova-issues

ActionEvent model fails to persist due to attribute casting issue causing action invocations to fail

Opened this issue · 1 comments

k8n commented
  • Laravel Version: 11.11.0
  • Nova Version: 4.34.1
  • PHP Version: 8.3.1
  • Database Driver & Version: pgsql
  • Operating System and Version: Ubuntu 20
  • Browser type and version: Chrome 114+

Description:

ActionEvent model sets the default created_at and updated_at attributes to new DateTime object in forSoftDeleteAction() (L251), forResourceDetach() (L286) and defaultAttributes() (L357). ActionEvent then uses static::insert() in createForModels() (L317) to persist new models. static::insert(), however, foregoes attribute casting, and escape() called from substituteBindingsIntoRawSql() of \Illuminate\Database\Query\Grammars\Grammar fails with the stack trace below.

This appears to be a new behaviour in my project, and possibly caused by recent Laravel package updates.

As a temporary workaround, I override the ActionEvent model class implementation via ActionResource specified in config/nova.php where I explicitly cast those dates, e.g.:

    public static function forSoftDeleteAction($action, $user, Collection $models)
    {
        return parent::forSoftDeleteAction($action, $user, $models)
            ->map(function ($actionEvent) {
                $actionEvent->created_at = ($actionEvent->created_at ?? now())->format((new self)->dateFormat);
                $actionEvent->updated_at = ($actionEvent->updated_at ?? now())->format((new self)->dateFormat);

                return $actionEvent;
            });
    }

If any of this appears misguided, I would appreciate any hints as to where to look to fix this casting issue; I may be missing something obvious.

Detailed steps to reproduce the issue on a fresh Nova installation:

Add any action to a resource in Nova (ensuring $withoutActionEvents is set to false). Invoke the action from the UI and watch it fail.

[2024-06-21 01:53:29] local.ERROR: str_contains(): Argument #1 ($haystack) must be of type string, DateTime given {"userId":12,"exception":"[object] (TypeError(code: 0): str_contains(): Argument #1 ($haystack) must be of type string, DateTime given at /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php:1107)
[stacktrace]
#0 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php(1107): str_contains()
#1 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Grammar.php(241): Illuminate\\Database\\Connection->escape()
#2 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Query/Grammars/Grammar.php(1501): Illuminate\\Database\\Grammar->escape()
#3 [internal function]: Illuminate\\Database\\Query\\Grammars\\Grammar->Illuminate\\Database\\Query\\Grammars\\{closure}()
#4 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Query/Grammars/Grammar.php(1501): array_map()
#5 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php(737): Illuminate\\Database\\Query\\Grammars\\Grammar->substituteBindingsIntoRawSql()
#6 /var/www/html/vendor/laravel/telescope/src/Watchers/QueryWatcher.php(95): Illuminate\\Database\\Query\\Grammars\\PostgresGrammar->substituteBindingsIntoRawSql()
#7 /var/www/html/vendor/laravel/telescope/src/Watchers/QueryWatcher.php(42): Laravel\\Telescope\\Watchers\\QueryWatcher->replaceBindings()
#8 /var/www/html/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(458): Laravel\\Telescope\\Watchers\\QueryWatcher->recordQuery()
#9 /var/www/html/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(286): Illuminate\\Events\\Dispatcher->Illuminate\\Events\\{closure}()
#10 /var/www/html/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(266): Illuminate\\Events\\Dispatcher->invokeListeners()
#11 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php(1073): Illuminate\\Events\\Dispatcher->dispatch()
#12 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php(842): Illuminate\\Database\\Connection->event()
#13 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php(777): Illuminate\\Database\\Connection->logQuery()
#14 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php(560): Illuminate\\Database\\Connection->run()
#15 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php(524): Illuminate\\Database\\Connection->statement()
#16 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(3608): Illuminate\\Database\\Connection->insert()
#17 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(2025): Illuminate\\Database\\Query\\Builder->insert()
#18 /var/www/html/vendor/laravel/framework/src/Illuminate/Support/Traits/ForwardsCalls.php(23): Illuminate\\Database\\Eloquent\\Builder->__call()
#19 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(2340): Illuminate\\Database\\Eloquent\\Model->forwardCallTo()
#20 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(2352): Illuminate\\Database\\Eloquent\\Model->__call()
#21 /var/www/html/vendor/laravel/nova/src/Actions/ActionEvent.php(317): Illuminate\\Database\\Eloquent\\Model::__callStatic()
#22 /var/www/html/vendor/laravel/framework/src/Illuminate/Collections/Traits/EnumeratesValues.php(259): Laravel\\Nova\\Actions\\ActionEvent::Laravel\\Nova\\Actions\\{closure}()
#23 /var/www/html/vendor/laravel/nova/src/Actions/ActionEvent.php(316): Illuminate\\Support\\Collection->each()
#24 /var/www/html/vendor/laravel/nova/src/Actions/DispatchAction.php(241): Laravel\\Nova\\Actions\\ActionEvent::createForModels()
#25 [internal function]: Laravel\\Nova\\Actions\\DispatchAction->Laravel\\Nova\\Actions\\{closure}()
#26 /var/www/html/vendor/laravel/nova/src/Concerns/InteractsWithActionEvent.php(38): call_user_func()
#27 /var/www/html/vendor/laravel/nova/src/Actions/DispatchAction.php(239): Laravel\\Nova\\Nova::usingActionEvent()
#28 /var/www/html/vendor/laravel/nova/src/Actions/Transaction.php(27): Laravel\\Nova\\Actions\\DispatchAction->Laravel\\Nova\\Actions\\{closure}()
#29 /var/www/html/vendor/laravel/nova/src/Actions/DispatchAction.php(238): Laravel\\Nova\\Actions\\Transaction::run()
#30 /var/www/html/vendor/laravel/nova/src/Actions/DispatchAction.php(224): Laravel\\Nova\\Actions\\DispatchAction->dispatchSynchronouslyForCollection()
#31 /var/www/html/vendor/laravel/nova/src/Actions/DispatchAction.php(177): Laravel\\Nova\\Actions\\DispatchAction->forModels()
#32 /var/www/html/vendor/laravel/nova/src/Http/Requests/ActionRequest.php(98): Laravel\\Nova\\Actions\\DispatchAction->Laravel\\Nova\\Actions\\{closure}()
#33 /var/www/html/vendor/laravel/framework/src/Illuminate/Collections/Traits/EnumeratesValues.php(259): Laravel\\Nova\\Http\\Requests\\ActionRequest->Laravel\\Nova\\Http\\Requests\\{closure}()
#34 /var/www/html/vendor/laravel/nova/src/Http/Requests/ActionRequest.php(97): Illuminate\\Support\\LazyCollection->each()
#35 /var/www/html/vendor/laravel/nova/src/Actions/DispatchAction.php(169): Laravel\\Nova\\Http\\Requests\\ActionRequest->chunks()
#36 /var/www/html/vendor/laravel/framework/src/Illuminate/Support/helpers.php(488): Laravel\\Nova\\Actions\\DispatchAction->Laravel\\Nova\\Actions\\{closure}()
#37 /var/www/html/vendor/laravel/nova/src/Actions/DispatchAction.php(116): with()
#38 /var/www/html/vendor/laravel/nova/src/Actions/Action.php(576): Laravel\\Nova\\Actions\\DispatchAction->dispatch()
#39 /var/www/html/vendor/laravel/nova/src/Http/Controllers/ActionController.php(60): Laravel\\Nova\\Actions\\Action->handleRequest()
#40 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Controller.php(54): Laravel\\Nova\\Http\\Controllers\\ActionController->store()
#41 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(43): Illuminate\\Routing\\Controller->callAction()
#42 /var/www/html/vendor/sentry/sentry-laravel/src/Sentry/Laravel/Tracing/Routing/TracingControllerDispatcherTracing.php(21): Illuminate\\Routing\\ControllerDispatcher->dispatch()
#43 /var/www/html/vendor/sentry/sentry-laravel/src/Sentry/Laravel/Tracing/Routing/TracingRoutingDispatcher.php(17): Sentry\\Laravel\\Tracing\\Routing\\TracingControllerDispatcherTracing->Sentry\\Laravel\\Tracing\\Routing\\{closure}()
#44 /var/www/html/vendor/sentry/sentry-laravel/src/Sentry/Laravel/Tracing/Routing/TracingControllerDispatcherTracing.php(20): Sentry\\Laravel\\Tracing\\Routing\\TracingRoutingDispatcher->wrapRouteDispatch()
#45 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Route.php(260): Sentry\\Laravel\\Tracing\\Routing\\TracingControllerDispatcherTracing->dispatch()
#46 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Route.php(206): Illuminate\\Routing\\Route->runController()
#47 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(806): Illuminate\\Routing\\Route->run()
#48 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(144): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}()
#49 /var/www/html/vendor/laravel/nova/src/Http/Middleware/Authorize.php(18): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#50 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Laravel\\Nova\\Http\\Middleware\\Authorize->handle()
#51 /var/www/html/vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php(64): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#52 /var/www/html/vendor/laravel/nova/src/Http/Middleware/Authenticate.php(31): Illuminate\\Auth\\Middleware\\Authenticate->handle()
#53 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Laravel\\Nova\\Http\\Middleware\\Authenticate->handle()
#54 /var/www/html/vendor/laravel/nova/src/Http/Middleware/BootTools.php(20): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#55 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Laravel\\Nova\\Http\\Middleware\\BootTools->handle()
#56 /var/www/html/vendor/laravel/nova/src/Http/Middleware/DispatchServingNovaEvent.php(33): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#57 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Laravel\\Nova\\Http\\Middleware\\DispatchServingNovaEvent->handle()
#58 /var/www/html/vendor/inertiajs/inertia-laravel/src/Middleware.php(86): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#59 /var/www/html/vendor/laravel/nova/src/Http/Middleware/HandleInertiaRequests.php(73): Inertia\\Middleware->handle()
#60 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Laravel\\Nova\\Http\\Middleware\\HandleInertiaRequests->handle()
#61 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php(88): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#62 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\\Foundation\\Http\\Middleware\\VerifyCsrfToken->handle()
#63 /var/www/html/vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php(49): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#64 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\\View\\Middleware\\ShareErrorsFromSession->handle()
#65 /var/www/html/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(121): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#66 /var/www/html/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(64): Illuminate\\Session\\Middleware\\StartSession->handleStatefulRequest()
#67 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\\Session\\Middleware\\StartSession->handle()
#68 /var/www/html/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php(37): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#69 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse->handle()
#70 /var/www/html/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php(75): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#71 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\\Cookie\\Middleware\\EncryptCookies->handle()
#72 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(119): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#73 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(805): Illuminate\\Pipeline\\Pipeline->then()
#74 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(784): Illuminate\\Routing\\Router->runRouteWithinStack()
#75 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(748): Illuminate\\Routing\\Router->runRoute()
#76 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(737): Illuminate\\Routing\\Router->dispatchToRoute()
#77 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(200): Illuminate\\Routing\\Router->dispatch()
#78 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(144): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}()
#79 /var/www/html/vendor/sentry/sentry-laravel/src/Sentry/Laravel/Http/FlushEventsMiddleware.php(13): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#80 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Sentry\\Laravel\\Http\\FlushEventsMiddleware->handle()
#81 /var/www/html/vendor/sentry/sentry-laravel/src/Sentry/Laravel/Http/SetRequestIpMiddleware.php(45): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#82 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Sentry\\Laravel\\Http\\SetRequestIpMiddleware->handle()
#83 /var/www/html/vendor/sentry/sentry-laravel/src/Sentry/Laravel/Http/SetRequestMiddleware.php(31): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#84 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Sentry\\Laravel\\Http\\SetRequestMiddleware->handle()
#85 /var/www/html/vendor/laravel/nova/src/Http/Middleware/ServeNova.php(23): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#86 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Laravel\\Nova\\Http\\Middleware\\ServeNova->handle()
#87 /var/www/html/vendor/barryvdh/laravel-debugbar/src/Middleware/InjectDebugbar.php(66): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#88 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Barryvdh\\Debugbar\\Middleware\\InjectDebugbar->handle()
#89 /var/www/html/vendor/laravel/framework/src/Illuminate/Http/Middleware/TrustProxies.php(57): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#90 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\\Http\\Middleware\\TrustProxies->handle()
#91 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#92 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull.php(31): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle()
#93 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull->handle()
#94 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#95 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php(51): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle()
#96 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\\Foundation\\Http\\Middleware\\TrimStrings->handle()
#97 /var/www/html/vendor/laravel/framework/src/Illuminate/Http/Middleware/ValidatePostSize.php(27): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#98 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\\Http\\Middleware\\ValidatePostSize->handle()
#99 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php(110): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#100 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance->handle()
#101 /var/www/html/vendor/sentry/sentry-laravel/src/Sentry/Laravel/Tracing/Middleware.php(97): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#102 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Sentry\\Laravel\\Tracing\\Middleware->handle()
#103 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(119): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#104 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(175): Illuminate\\Pipeline\\Pipeline->then()
#105 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(144): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter()
#106 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(1183): Illuminate\\Foundation\\Http\\Kernel->handle()
#107 /var/www/html/public/index.php(17): Illuminate\\Foundation\\Application->handleRequest()
#108 /var/www/html/server.php(21): require_once('...')
#109 {main}
"} 

Please provide full reproducing repository based on fresh installation as suggested in the bug report template (or you can refer to https://github.com/nova-issues for example)