laravel-actions icon indicating copy to clipboard operation
laravel-actions copied to clipboard

Handle ValidationException when using asCommand and validating in handle()

Open jonagoldman opened this issue 2 years ago • 2 comments

Hi, I'm using v2.5.1 of this package with Laravel v10.1.3.

To ensure data always gets validated no matter how the action is called, I'm using unified attributes to manually validate directly in the handle() method. This works fine when the action is running as a controller, so if when the validation fails, the exception is handled correctly, but when the validation fails running as a command it is not handled.

Full example:

<?php

namespace App\Account\Actions;

use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Password as PasswordRule;
use Lorisleiva\Actions\ActionRequest;
use Lorisleiva\Actions\Concerns\AsAction;
use Lorisleiva\Actions\Concerns\WithAttributes;

class CreateUser
{
    use AsAction;
    use WithAttributes;

    public string $commandSignature = 'register:user';

    public string $commandDescription = 'Register a new user.';

    public function rules(): array
    {
        return [
            'name' => ['required', 'string', 'min:3', 'max:192'],
            'email' => ['required', 'max:192', 'email', Rule::unique('users')],
            'password' => ['required', 'confirmed', PasswordRule::default()],
        ];
    }

    public function handle(array $attributes = []): User
    {
        $this->fill($attributes);
        $validated = $this->validateAttributes();
        $user = User::create($validated);
        return $user;
    }

    public function asController(ActionRequest $request)
    {
        $this->fillFromRequest($request);
        $user = $this->handle();
        return $user;
    }

    public function asCommand(Command $command)
    {
        $attributes = [];

        $attributes['name'] = $command->ask('Name?', 'User 1');
        $attributes['email'] = $command->ask('Email?', '[email protected]');
        $attributes['password'] = $command->secret('Password?');
        $attributes['password_confirmation'] = $command->secret('Password Confirmation?');

        $user = $this->handle($attributes);

        $command->info('User registered!');
    }
}

Console result: Screenshot_20230223_203437

I can catch the exception locally inside the asCommand() method:

try {
    $user = $this->handle($attributes);
} catch (\Illuminate\Validation\ValidationException $exception) {
    $command->error($exception->getMessage());
    return Command::INVALID;
}

$command->info('User registered!');
return Command::SUCCESS;

But I wonder if there is a better, cleaner way, and I don't have to do this on every action. I don't know if it needs to be handled inside the package or in the app itself.

Thanks.

jonagoldman avatar Feb 23 '23 23:02 jonagoldman