lorisleiva / laravel-actions

⚡️ Laravel components that take care of one specific task
https://laravelactions.com
MIT License
2.5k stars 123 forks source link

Using validation and authorization without running as a controller #175

Closed nathan-io closed 1 week ago

nathan-io commented 2 years ago

I read the "Add validation to your controllers" doc.

We have a Livewire component which provides UI for CRUD of a resource (Phone, for example).

While Livewire provides validate() as a way of validating the request against the defined rules, I'm wondering if we should forgo that and instead centralize validation rules (and authorization, for that matter) in the Action class.

Here's a current work in progress implementation which is using the Validator facade for now:

CreatePhoneAction class:

    public function handle($data, $userId) {
        $validator = Validator::make($data, [
            // our rules
        ]);

        if ($validator->fails()) {
            return [
                'success' => false,
                'data' => $validator->errors()->all(),
            ];
        }

        $phone = Phone::create($validator->validated());

        return [
            'success' => true,
            'data' => $phone,
        ];
     }

In the Livewire component class, our method which handles creation:

    public function create()
    {
        $data = $this->getFormData();

        $response = CreatePhoneAction::run(data: $data, userId: Auth::id());

        if($response['success']) {
            $this->emit('modal-close', 'phone_modal');
            $this->alert('success', 'Phone saved successfully!');
            $this->emit('refreshParentTable');
            return;
        } else{
            foreach($response['data'] as $i => $errorItem){
                $this->addError('error-' . $i, $errorItem);
            }
        }

    }

As you can see, we're currently not leveraging the rules() or authorize() methods provided by ActionRequest.

While this action isn't being run as a controller and there's no route that it's registered to, it could still receive a Request from Livewire, which we can validate and authorize.

I believe this question only arises in situations where we're using a Livewire component to handle CRUD rather than traditional resource routes.

Hope this makes sense. I'm admittedly still learning about the package and the action pattern. It's also possible that I'm thinking about this in the wrong way.

I appreciate any suggestions or feedback.

onemoreahmad commented 2 years ago

If I understand you well, I think you can use $action->fillFromRequest($request) in your handle method, for example:

   public function handle(array $attributes = [])
    {
        $this->fill($attributes);
        $validatedData = $this->validateAttributes();

        $phone = Phone::create($validator->validated());

        return [
            'success' => true,
            'data' => $phone,
        ];
    }

Don't forget to use WithAttributes trait for this to work.

Wulfheart commented 1 week ago

@lorisleiva Is it ok if I close inactive/old issues?

lorisleiva commented 1 week ago

@Wulfheart Go for it! Thanks for The housekeeping. 🫶

Wulfheart commented 1 week ago

Closing due to inactivity. If you feel your issue is still relevant please open a new one with a link to a repository containing a minimal reproducible example.