mvanduijker/laravel-model-exists-rule
composer require mvanduijker/laravel-model-exists-rule in your project root.php artisan vendor:publish --provider="Duijker\LaravelModelExistsRule\ServiceProvider" for customization.use Duijker\LaravelModelExistsRule\ModelExists;
// In your FormRequest or controller
$rules = [
'user_id' => ['required', new ModelExists(\App\Models\User::class, 'id')],
];
tests/ for edge cases and real-world usage patterns.src/ModelExists.php to understand customization options.Simple Existence Check:
new ModelExists(\App\Models\User::class, 'id')
Validates if a record exists in the users table with the given id.
Custom Query Builder Logic:
new ModelExists(\App\Models\Post::class, 'slug')
->where('published', true)
->whereHas('author', fn($q) => $q->where('active', true))
Extend with Eloquent query methods for complex conditions.
Dynamic Model/Column:
$modelClass = $request->input('model');
$column = $request->input('column');
new ModelExists($modelClass, $column)
Useful for polymorphic validation (e.g., admin panels).
App\Http\Requests for reusability.$user = \App\Models\User::find($request->user_id);
return new UserResource($user);
new ModelExists(\App\Models\User::class, 'id')
->message('The selected user does not exist.'),
Soft Deletes:
new ModelExists(\App\Models\Order::class, 'id')
->withTrashed()
Include soft-deleted records in validation.
Scopes:
new ModelExists(\App\Models\Product::class, 'sku')
->where('category_id', $request->category_id)
->scope('active')
Leverage model scopes for reusable query logic.
Conditional Validation:
$validator = Validator::make($request->all(), [
'user_id' => [
new ModelExists(\App\Models\User::class, 'id'),
Rule::unique('users')->ignore($request->user_id), // Avoid self-validation
],
]);
Case Sensitivity:
id vs ID).snake_case consistently or cast columns in the rule:
new ModelExists(\App\Models\User::class, 'ID')->castColumn('id');
Eager Loading Pitfalls:
whereHas or with can trigger N+1 queries if not optimized.withCount() or loadMissing() for performance:
new ModelExists(\App\Models\Post::class, 'id')
->withCount('comments')
->having('comments_count', '>', 0)
Model Events:
retrieved). Useful for side effects like logging.Caching:
new ModelExists(\App\Models\User::class, 'id')
->useCache()
->cacheFor(seconds: 300);
Query Logs: Enable Laravel’s query logging to inspect generated SQL:
DB::enableQueryLog();
$validator = Validator::make([...], [...]);
dd(DB::getQueryLog());
Custom Validation Logic:
Override the passes() method in a custom rule class if default behavior is insufficient:
class CustomModelExists extends ModelExists {
public function passes($attribute, $value) {
return $this->builder->where('active', true)->exists();
}
}
Custom Builders: Inject a pre-built query:
$builder = \App\Models\User::query()->where('role', 'admin');
new ModelExists($builder, 'id');
Dynamic Model Resolution: Resolve models dynamically (e.g., from a config or service container):
$model = app()->make($request->model_class);
new ModelExists($model, 'id');
Testing: Mock the rule in tests to avoid database hits:
$rule = new ModelExists(\App\Models\User::class, 'id');
$rule->shouldReceive('passes')->andReturn(true);
exists() under the hood, which is efficient but doesn’t load the model.resources/lang) or inline:
->message('custom.error.message'),
SoftDeletes trait and the deleted_at column exists.Combine with Other Rules:
new ModelExists(\App\Models\User::class, 'id')
->sometimesRequired()
->when($request->has('admin'), function ($rule) {
return $rule->where('role', 'admin');
}),
Bulk Validation: Validate multiple IDs at once:
$ids = explode(',', $request->user_ids);
$valid = collect($ids)->every(fn($id) =>
new ModelExists(\App\Models\User::class, 'id')->passes('user_id', $id)
);
API Rate Limiting:
Pair with throttle rules to prevent abuse:
$rules = [
'user_id' => [
new ModelExists(\App\Models\User::class, 'id'),
Rule::throttle('user-lookup', 10)->every(15),
],
];
How can I help you explore Laravel packages today?