laravel / nova-issues

556 stars 34 forks source link

Dispatching actions automatically from Observer #400

Closed Alymosul closed 6 years ago

Alymosul commented 6 years ago

Let's say I have a User resource and I want to dispatch the send Email action from the UserObserver... is this doable in Nova? I don't want to create an Event for the email action and trigger it from the UserObserver/Email Action.

thannaske commented 6 years ago

If I get your request right you could just add a custom action and dispatch the action from there (see: https://nova.laravel.com/docs/1.0/actions/defining-actions.html#overview).

Alymosul commented 6 years ago

What I mean is that I have a UserObserver class as follows:

class UserObserver
{
    public function created(Contractor $contractor)
    {
      // I want to dispatch the action here..
    }
}
Alymosul commented 6 years ago

I think I found a way to do it as follows:

class UserObserver 
{
    public function created(Contractor $contractor)
    {
        $collection = Collection::wrap($contractor);

        $action = new SendEmailAction;

        $request = app(ActionRequest::class);

        $request->action = $action->uriKey();

        DispatchAction::forModels($request, $action, 'handle', $collection);
    }
}
HUN-Julian commented 6 years ago

I think I found a way to do it as follows:

class UserObserver 
{
    public function created(Contractor $contractor)
    {
        $collection = Collection::wrap($contractor);

        $action = new SendEmailAction;

        $request = app(ActionRequest::class);

        $request->action = $action->uriKey();

        DispatchAction::forModels($request, $action, 'handle', $collection);
    }
}

Hi,

Could you please send the full Observer code? I have some problem with mine... Thanks in advance!

Alymosul commented 6 years ago

@HUN-Julian this is my full observer code. Explain your problem and maybe i can help.

HUN-Julian commented 6 years ago

@Alymosul Thanks for your help, but I did the job as follows:

observer:

class OrderObserver { /**

Action

... use Illuminate\Foundation\Bus\Dispatchable; ... class OrderImport extends Action implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; ...

Alymosul commented 6 years ago

I think it won't work because the dispatch for Actions is a bit different than for the normal laravel jobs, as i did in my observer code, you must have the current request and attach the desired action to it before dispatching it using dispatch forModels()...

HUN-Julian commented 6 years ago

@Alymosul Hi, Unfortunately, your code is not working for me, because it said that error:

[2018-09-21 16:12:13] local.ERROR: Argument 4 passed to Laravel\Nova\Actions\CallQueuedAction::__construct() must be an instance of Illuminate\Database\Eloquent\Collection, instance of Illuminate\Support\Collection given, called in /var/www/clients/client1/web13/web/nova/src/Actions/DispatchAction.php on line 57

(Symfony\Component\Debug\Exception\FatalThrowableError(code: 0): Argument 4 passed to Laravel\Nova\Actions\CallQueuedAction::__construct() must be an instance of Illuminate\Database\Eloquent\Collection, instance of Illuminate\Support\Collection given, called in /var/www/clients/client1/web13/web/nova/src/Actions/DispatchAction.php on line 57 at /var/www/clients/client1/web13/web/nova/src/Actions/CallQueuedAction.php:30)

[stacktrace] 0 /var/www/clients/client1/web13/web/nova/src/Actions/DispatchAction.php(57): Laravel\Nova\Actions\CallQueuedAction->__construct(Object(App\Nova\Actions\OrderProcess), 'handle', Object(Laravel\Nova\Fields\ActionFields), Object(Illuminate\Support\Collection), '8bd69f62-b335-4...')

Here's my full code:

namespace App\Observers;

use App\Order; use App\Nova\Actions; use Illuminate\Support\Facades\Log; use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; use App\Nova\Actions\OrderProcess; use Laravel\Nova\Http\Requests\ActionRequest; use Laravel\Nova\Actions\DispatchAction;

class OrderObserver { /**

Am i forget something?

Alymosul commented 6 years ago

@HUN-Julian yes! you should import Illuminate\Database\Eloquent\Collection instead of Illuminate\Support\Collection in the OrderObserver class (at the beginning of the file)

HUN-Julian commented 6 years ago

Ugh, you're right... 👍 I've just started learning Laravel & Nova duo. Thanks a lot, it works very well for now!

davidhemphill commented 6 years ago

Seems like you figured it out, so I'm gonna close this. :-)

larsjanssen6 commented 6 years ago

@Alymosul when I try that I get Call to a member function getKey() on null any idea? Do I have to set a user on the request?

dillingham commented 6 years ago

Would be cool to have a helper method on the action itself

(new SendEmailAction)->dispatch($fields, $models);
larsjanssen6 commented 6 years ago

That ^ makes sense because right now it's a bit clunky.

Alymosul commented 6 years ago

@larsjanssen6 You have to know which line causing the problem but the authenticated user should be already set on the request and you should have this activity available to the resource..

rjvandoesburg commented 5 years ago

So I was using this code to dispatch actions for models, however it stopped working. When I updated $request->action = $action->uriKey(); to $request->query->set('action', $action->uriKey()); the action was dispatched again.

Call for action is being made in Laravel\Nova\Http\Requests\ActionRequest:23 $this->query('action')

Anyone knows if there is another solution for running actions from observers?

johnpaulmedina commented 5 years ago

@rjvandoesburg You need to include the ActionFields as well now:

        $collection = Collection::wrap($user);
        $action = new SendAccountProfile;
        $request = app(ActionRequest::class);
        $request->action = $request->query->set('action', $action->uriKey());
        $fields = $request->resolveFields();
        DispatchAction::forModels($request, $action, 'handle', $collection, $fields);
shattique commented 5 years ago

Above code by johnpaulmedina works well, it triggers the handle function. But I'm having a different issue if anyone can help me out, I'm trying to figure this out for last 3 days. I have a Action::redirect to external url in the handle function of the custom action which is not working. I need to send to an external page to generate token when resource is created.

Anyone knows if there is a way to redirect to external url after a resource is created?

feldsam commented 4 years ago

Hi all, the above code working fine if dispatching actions from the browser. For example, when an observer is called on some user action in the browser. Problem is, when I try to dispatch actions from console commands, it ends with a 404 error. Looks like this line $request = app(ActionRequest::class); doesn't return the same thing as when executed from the browser.

Any advice on this? Thank you in advance!

asanchez19 commented 2 months ago

Above code by johnpaulmedina works well, it triggers the handle function. But I'm having a different issue if anyone can help me out, I'm trying to figure this out for last 3 days. I have a Action::redirect to external url in the handle function of the custom action which is not working. I need to send to an external page to generate token when resource is created.

Anyone knows if there is a way to redirect to external url after a resource is created? Did you figure it out? I'm running into the same issue on 2024 :(