Installation:
composer require sofa/eloquence-validable
Add the trait to your Eloquent model:
use Sofa\Eloquence\Validable\Validable;
class User extends Model
{
use Validable;
}
Define Validation Rules:
Override the rules() method in your model:
protected function rules(): array
{
return [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
];
}
First Use Case: Validate a model instance:
$user = new User(['name' => 'John', 'email' => 'invalid-email']);
if ($user->isValid()) {
$user->save(); // Only saves if valid
} else {
// Handle errors: $user->errors()
}
rules() method: Core validation logic.errors() method: Access validation error messages.isValid() method: Check if the model passes validation.validate() method: Explicitly trigger validation.// Validate on creation/update
$user = new User(['name' => 'Jane']);
if ($user->isValid()) {
$user->save();
}
// Validate existing record
$user->name = 'Updated Name';
$user->validate(); // Re-validate
Use rules() dynamically with closures:
protected function rules(): array
{
return [
'email' => function ($email) {
return $email ? 'required|email' : 'nullable';
},
];
}
Override messages():
protected function messages(): array
{
return [
'name.required' => 'The name field is mandatory!',
];
}
Validate collections or single models:
$users = User::where('active', true)->get()->filter->isValid();
Use with Laravel's Form Requests or frontend validation:
// In a FormRequest
public function rules()
{
return (new User())->rules(); // Reuse model rules
}
Extend with validateCustom():
protected function validateCustom()
{
if ($this->age < 18) {
$this->errors()->add('age', 'Must be at least 18.');
}
}
Validate before serialization:
public function toArray($request)
{
$this->validate();
return [
'data' => $this->only(['name', 'email']),
];
}
Validate in saving/updating:
public function saving(Model $model)
{
if (!$model->isValid()) {
throw new \Exception('Validation failed');
}
}
Assert validation errors:
$response = $this->post('/users', ['email' => 'invalid']);
$response->assertJsonValidationErrors(['email']);
Rule Overrides:
rules() is merged, not overwritten:
protected function rules(): array
{
return array_merge(parent::rules(), [
'new_field' => 'required',
]);
}
Lazy Validation:
isValid() runs rules only when called. For eager validation, use validate() explicitly.Mass Assignment:
$fillable or $guarded carefully.Custom Logic Timing:
validateCustom() runs after rule validation. Use it for post-validation checks.Nested Model Validation:
User::with('posts')->get()), validate each manually:
$user->posts->each->validate();
Inspect Errors:
dd($model->errors()->all());
Disable Rules Temporarily:
$model->setRules([]); // Clear rules
Check Rule Sources:
rules() method.FormRequest).Validate Partial Data:
$model->validate(['name' => 'Test']); // Validate specific fields
Custom Validators: Add reusable validators to the model:
protected function customValidators(): array
{
return [
'unique_username' => function ($username) {
return User::where('username', $username)->exists()
? 'Username taken'
: null;
},
];
}
Dynamic Rule Generation: Use closures for context-aware rules:
protected function rules(): array
{
return [
'password' => function ($password, $model) {
return $model->exists
? 'sometimes|string|min:8'
: 'required|string|min:8';
},
];
}
Event-Based Validation: Trigger validation on events:
$model->on('validating', function ($model) {
// Pre-validation logic
});
Override Validation Logic: Extend the trait to modify behavior:
trait CustomValidable
{
public function validate()
{
// Custom logic
parent::validate();
}
}
config/eloquence.php).rules() override earlier ones for the same field.Validator instance. Use errors() to access them.How can I help you explore Laravel packages today?