Laravel Magic Scopes auto-generates query scopes for your models — no code needed, just magic 🔮.
You can install the package via composer:
composer require safemood/laravel-magic-scopesYou can publish the config file with:
php artisan vendor:publish --tag="magic-scopes-config"This is the contents of the published config file:
<?php
declare(strict_types=1);
return [
'resolvers' => [
\Safemood\MagicScopes\Resolvers\BooleanFieldScopeResolver::class,
\Safemood\MagicScopes\Resolvers\DateFieldScopeResolver::class,
\Safemood\MagicScopes\Resolvers\EnumFieldScopeResolver::class,
\Safemood\MagicScopes\Resolvers\ForeignKeyFieldScopeResolver::class,
\Safemood\MagicScopes\Resolvers\JsonFieldScopeResolver::class,
\Safemood\MagicScopes\Resolvers\NumberFieldScopeResolver::class,
\Safemood\MagicScopes\Resolvers\StringFieldScopeResolver::class,
],
];Simply use the HasMagicScopes trait in your Eloquent model:
use Safemood\MagicScopes\Traits\HasMagicScopes;
class Post extends Model
{
use HasMagicScopes;
}$posts = Post::where('views', '>', 216) // query
->notPublished() // magic scope
->recent() // real scope
->createdAfter('2025-05-01') // magic scope
->get();Post::published()->get(); // where('is_published', true)
Post::notPublished()->get(); // where('is_published', false)
Post::hasFeaturedImage()->get(); // where('has_featured_image', true)
Post::hasNotFeaturedImage()->get(); // where('has_featured_image', false)
Post::sticky()->get(); // where('is_sticky', true)
Post::notSticky()->get(); // where('is_sticky', false)Post::statusIs('published')->get(); // where('status', 'published')
Post::typeIs('announcement')->get(); // where('type', 'announcement')Post::forUser(1)->get(); // where('user_id', 1)
Post::forCategory([1, 2])->get(); // whereIn('category_id', [1, 2])
Post::withUser()->get(); // with('user')
Post::withUser([1, 2])->get(); // with(['user' => fn ($q) => $q->whereIn('id', [1, 2])])
Post::withAuthor(10)->get(); // with(['author' => fn ($q) => $q->where('id', 10)])
NOTE:
The relationships ('user', 'author') must be properly defined on the `Post` model (at least for now 😉)Post::rentRequestsContains('rooms_count', 2)->get(); // whereJsonContains('rent_requests->rooms_count', 2)
Post::rentContains('city', 'Tunis')->get(); // whereJsonContains('rent->city', 'Tunis')
Post::settingsContains('timezone', 'UTC')->get(); // whereJsonContains('settings->timezone', 'UTC')Post::whereViewsGreaterThan(50)->get(); // where('views', '>', 50)
Post::whereScoreEquals(90)->get(); // where('score', '=', 90)
Post::wherePriceBetween(100, 200)->get(); // whereBetween('price', [100, 200])
Post::whereDownloadsEquals(10)->get(); // where('downloads', '=', 10)Post::reviewedAt('2024-05-10')->get(); // Equivalent to: whereDate('reviewed_at', '2024-05-10')
Post::reviewedBefore('2024-05-15')->get(); // Equivalent to: whereDate('reviewed_at', '<', '2024-05-15')
Post::reviewedAfter('2024-05-15')->get(); // Equivalent to: whereDate('reviewed_at', '>', '2024-05-15')
Post::reviewedBetween('2024-05-10', '2024-05-20')->get(); // Equivalent to: whereBetween('reviewed_at', ['2024-05-10', '2024-05-20'])You can create your own custom scope resolver if you want to control how scopes are resolved from method names.
Here's how to create a custom ScopeResolver:
Custom resolvers should not match the same method as another resolver.
If multiple resolvers match, an exception is thrown to avoid conflicts.
<?php
declare(strict_types=1);
namespace Safemood\MagicScopes\Resolvers;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Safemood\MagicScopes\Contracts\ScopeResolverContract;
class CustomScopeResolver implements ScopeResolverContract
{
public function matches(string $method, Builder $builder): bool
{
return Str::startWith($method, 'customPrefix');
}
public function apply(Builder $query, string $method, array $parameters, Model $model): Builder
{
$column = 'your_column_name'; // extract from method name
$value = $parameters[0] ?? null; // get the value, depending on your logic
$builder->where($column, $value); // Apply basic WHERE condition
return $query; // Always return the original query builder after applying conditions
}
}composer testPlease see CHANGELOG for more information on what has changed recently.
Please see CONTRIBUTING for details.
Please review our security policy on how to report security vulnerabilities.
The MIT License (MIT). Please see License File for more information.