Validating command parameters in Laravel

By Luis Güette

As Laravel developers, we create many complex commands for our applications. One question that always arises when creating commands is how to validate input parameters.

Laravel commands offer a lot of flexibility when it comes to argument and option inputs. However, ensuring that the user is passing the right parameters is an important step in creating a solid command.

Enter Laravel's Validator facade! This powerful tool allows us to validate input parameters in a simple and efficient way.

To demonstrate how to use Validator, let's create a command to create users with various input parameters. First, we will define the command signature:

namespace App\Console\Commands;
 
use Illuminate\Console\Command;
 
class CreateUserCommand extends Command
{
protected $signature = 'create:user
{email : The email of the user}
{--name= : The name of the user}
{--password= : The password of the user}';
 
protected $description = 'Create a new user';
 
public function handle(): void
{
 
}
}

We define email as a required argument, and name and password as options.

Next, we add a validateArguments() method to validate the email, returning an array of validated input parameters if it is valid:

namespace App\Console\Commands;
 
use App\Models\User;
use Illuminate\Console\Command;
use Validator;
 
class CreateUserCommand extends Command
{
protected $signature = 'create:user
{email : The email of the user}
{--name= : The name of the user}
{--password= : The password of the user}';
 
protected $description = 'Create a new user';
 
public function handle(): void
{
$arguments = $this->validateArguments();
}
 
protected function validateArguments(): ?array
{
$validator = Validator::make($this->arguments(), [
'email' => ['required', 'email', 'unique:users,email'],
]);
 
if ($validator->fails()) {
$this->error('Whoops! The given attributes are invalid.');
 
collect($validator->errors()->all())
->each(fn ($error) => $this->line($error));
exit;
}
 
return $validator->validated();
}
}

We do a similar thing with the options, creating a validateOptions() method, where we’ll validate name and password:

namespace App\Console\Commands;
 
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Validation\Rules\Password;
use Validator;
 
class CreateUserCommand extends Command
{
protected $signature = 'create:user
{email : The email of the user}
{--name= : The name of the user}
{--password= : The password of the user}';
 
protected $description = 'Create a new user';
 
public function handle(): void
{
//...
$options = $this->validateOptions();
}
 
//...
 
protected function validateOptions(): ?array
{
$validator = Validator::make($this->options(), [
'name' => ['nullable', 'string', 'min:2', 'max:20'],
'password' => [
'nullable',
Password::min(8)
->letters()
->mixedCase()
->numbers()
->symbols(),
],
]);
 
if ($validator->fails()) {
$this->error('Whoops! The given options are invalid.');
 
collect($validator->errors()->all())
->each(fn ($error) => $this->line($error));
exit;
}
 
return $validator->validated();
}
}

Finally, if the data is valid, we create the user.

Now, let’s move these methods to a trait called ValidatesInputs we can reuse it in other commands.

namespace App\Traits;
 
use Illuminate\Console\Concerns\HasParameters;
use Illuminate\Console\Concerns\InteractsWithIO;
use Validator;
 
trait ValidatesInputs
{
use HasParameters;
use InteractsWithIO;
 
public function validate(array $argumentRules = null, $optionRules = null): array
{
$arguments = $argumentRules
? $this->validateArguments($this->arguments(), $argumentRules)
: $this->arguments();
 
$options = $optionRules
? $this->validateOptions($this->options(), $optionRules)
: $this->options();
 
return [$arguments, $options];
}
 
protected function validateOptions(array $options = [], array $rules = []): ?array
{
$validator = Validator::make($options, $rules);
 
if ($validator->fails()) {
$this->error('Whoops! The given options are invalid.');
 
collect($validator->errors()->all())
->each(fn ($error) => $this->line($error));
exit;
}
 
return $validator->validated();
}
 
protected function validateArguments(array $arguments = [], array $rules = []): ?array
{
$validator = Validator::make($arguments, $rules);
 
if ($validator->fails()) {
$this->error('Whoops! The given attributes are invalid.');
 
collect($validator->errors()->all())
->each(fn ($error) => $this->line($error));
exit;
}
 
return $validator->validated();
}
}

Now, we can use this trait in the command like this:

namespace App\Console\Commands;
 
use App\Models\User;
use App\Traits\ValidateInputs;
use Illuminate\Console\Command;
use Illuminate\Validation\Rules\Password;
 
class CreateUserCommand extends Command
{
use ValidatesInputs;
 
protected $signature = 'create:user
{email : The email of the user}
{--name= : The name of the user}
{--password= : The password of the user}';
 
protected $description = 'Create a new user';
 
public function handle(): void
{
[$arguments, $options] = $this->validate(
argumentRules: [
'email' => ['required', 'email', 'unique:users,email'],
],
optionRules: [
'name' => ['nullable', 'string', 'min:2', 'max:20'],
'password' => [
'nullable',
Password::min(8)
->letters()
->mixedCase()
->numbers()
->symbols(),
],
]);
 
User::create([
'name' => $options['name'],
'email' => $arguments['email'],
'password' => $arguments['password'],
]);
}
}

Finally, let’s run our command with some invalid name and password data:

╰─❯ php artisan create:user luis@test.com --name=a --password=12
Whoops! The given options are invalid.
The name field must be at least 2 characters.
The password field must be at least 8 characters.
The password field must contain at least one uppercase and one lowercase letter.
The password field must contain at least one letter.
The password field must contain at least one symbol.

Laravel's Validator facade is a powerful tool for validating command input parameters. By implementing a Validator in our Laravel command, we can ensure that our commands receive the correct input parameters. This can help make our commands more reliable and avoid storing invalid data. By using a trait, we can extend this functionality to other commands that need validation.

With these tools in your toolbox, you can create Laravel commands with confidence, knowing that they will be able to handle unexpected input data while still performing the desired action.

Luis Güette
Web Application Developer
Author Image

Interested in speaking with a developer?

Connect with us.
©2024 Kirschbaum Development Group LLC Privacy Policy Terms of Service