Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Eloquent Filtering Laravel Package

indexzer0/eloquent-filtering

Filter Laravel Eloquent models using simple arrays and request data—no custom query spaghetti. Define allowed filters on your models, support complex search, and keep queries readable, maintainable, and easy to extend for APIs and dashboards.

View on GitHub
Deep Wiki
Context7

title: 'Pivot Filters' version: 'v2' icon: 'scale-unbalanced' iconType: 'solid'

Overview

Pivot filters can be specified in two ways:

  • on Custom Intermediate Table Models (Pivot, MorphPivot).
  • on your main models (Model).

With Custom Intermediate Table Models

If you are utilising Custom Intermediate Table Models, you may define filters on that model.

Filters defined on this model will be applied to the intermediate table.

/*
 * User Model
 */
class User extends Model implements IsFilterable
{
    use Filterable;

    public function roles(): BelongsToMany
    {
        return $this->belongsToMany(Role::class)->using(RoleUser::class);
    }

    public function allowedFilters(): AllowedFilterList
    {
        return Filter::only(
            Filter::relation('roles', [FilterType::HAS])->includeRelationFields(),
        );
    }
}

/*
 * Role Model
 */
class Role extends Model implements IsFilterable
{
    use Filterable;

    public function users(): BelongsToMany
    {
        return $this->belongsToMany(User::class)->using(RoleUser::class);
    }

    public function allowedFilters(): AllowedFilterList
    {
        return Filter::only(
            Filter::relation('users', [FilterType::HAS])->includeRelationFields(),
        );
    }
}

/*
 * RoleUser Pivot Model
 */
class RoleUser extends Pivot implements IsFilterable
{
    use Filterable;

    public function allowedFilters(): AllowedFilterList
    {
        return Filter::only(
            Filter::field('assigned_by', [FilterType::EQUAL]),
        );
    }
}

/*
 * Applying `assigned_by` pivot filter
 * within `roles` `$has` relation filter.
 */
User::filter([
    [
        'type'   => '$has',
        'target' => 'roles',
        'value'  => [
            [
                'type'   => '$eq',
                'target' => 'assigned_by',
                'value'  => 'admin',
            ]
        ]
    ]
]);

/*
 * Applying `assigned_by` pivot filter
 * within `users` `$has` relation filter.
 */
Role::filter([
    [
        'type'   => '$has',
        'target' => 'users',
        'value'  => [
            [
                'type'   => '$eq',
                'target' => 'assigned_by',
                'value'  => 'admin',
            ]
        ]
    ]
]);

Restricting Allowed Pivot Filters.

Sometimes you may only want the pivot filter to be allowed when filtering by relationship one way but not the other way.

For example:

  • Allowed when filtering User $has Role.
  • Denied when filtering Role $has User.

To achieve this you can specify the allowed "from" model for the pivot filter.

/*
 * RoleUser Pivot Model
 */
class RoleUser extends Pivot implements IsFilterable
{
    use Filterable;

    public function allowedFilters(): AllowedFilterList
    {
        return Filter::only(
            Filter::field('assigned_by', [FilterType::EQUAL])
                ->pivot(User::class),
        );
    }
}

Without Custom Intermediate Table Models

If you are NOT utilising Custom Intermediate Table Models, you may define pivot filters on your main models.

Filter::field() filters can be marked as pivot filters if you want the filter to be applied to a column on the intermediate table linking the models.

You must specify the parent model fqcn.

public function allowedFilters(): AllowedFilterList
{
    return Filter::only(
        Filter::field('tagged_by', [FilterType::EQUAL])
            ->pivot(Post::class),
    );
}

BelongsToMany

In the below example of class Post and class Tag.

  • The pivot filter is specified in the allowedFilters method of both classes.
  • The pivot filter can only be used when in the context of the posts or tags relationship.
class Post extends Model implements IsFilterable
{
    use Filterable;

    public function tags(): BelongsToMany
    {
        return $this->belongsToMany(Tag::class);
    }

    public function allowedFilters(): AllowedFilterList
    {
        return Filter::only(
            Filter::field('tagged_by', [FilterType::EQUAL])->pivot(Tag::class),
            Filter::relation('tags', [FilterType::HAS])->includeRelationFields()
        );
    }
}

class Tag extends Model implements IsFilterable
{
    use Filterable;

    public function posts(): BelongsToMany
    {
        return $this->belongsToMany(Post::class);
    }

    public function allowedFilters(): AllowedFilterList
    {
        return Filter::only(
            Filter::field('tagged_by', [FilterType::EQUAL])->pivot(Post::class),
            Filter::relation('posts', [FilterType::HAS])->includeRelationFields()
        );
    }
}

Allowed

With the models setup as described above. The following filters are allowed.

/*
 * Applying `tagged_by` pivot filter
 * within `tags` `$has` relation filter.
 */
Post::filter([
    [
        'type'   => '$has',
        'target' => 'tags',
        'value'  => [
            [
                'type'   => '$eq',
                'target' => 'tagged_by',
                'value'  => 'admin',
            ]
        ]
    ]
]);

/*
 * Applying `tagged_by` pivot filter
 * within `posts` `$has` relation filter.
 */
Tag::filter([
    [
        'type'   => '$has',
        'target' => 'posts',
        'value'  => [
            [
                'type'   => '$eq',
                'target' => 'tagged_by',
                'value'  => 'admin',
            ]
        ]
    ]
]);

DeniedFilterException

With the models setup as described above. The following filters are denied.

/*
 * Applying `tagged_by` pivot filter
 * when not in context of `tags` `$has` relation filter.
 * throws DeniedFilterException.
 */
Post::filter([
    [
        'type'   => '$eq',
        'target' => 'tagged_by',
        'value'  => 'admin',
    ]
]);

/*
 * Applying `tagged_by` pivot filter
 * when not in context of `posts` `$has` relation filter.
 * throws DeniedFilterException.
 */
Tag::filter([
    [
        'type'   => '$eq',
        'target' => 'tagged_by',
        'value'  => 'admin',
    ]
]);

/*
 * Applying `tagged_by` pivot filter
 * when in context of another BelongsToMany relation
 * but User::class not defined in the ->pivot() method in the tags model.
 * throws DeniedFilterException.
 */
User::filter([
    [
        'type'   => '$has',
        'target' => 'tags',
        'value'  => [
            [
                'type'   => '$eq',
                'target' => 'tagged_by',
                'value'  => 'admin',
            ]
        ]
    ]
]);

MorphToMany (Polymorphic)

When defining a pivot filter for MorphToMany relations, you can specify a list of models in the ->pivot() method.

class Epic extends Model implements IsFilterable
{
    // ...
    public function allowedFilters(): AllowedFilterList
    {
        return Filter::only(
            Filter::relation('labels', [FilterType::HAS])->includeRelationFields()
        );
    }
}

class Issue extends Model implements IsFilterable
{
    // ...
    public function allowedFilters(): AllowedFilterList
    {
        return Filter::only(
            Filter::relation('labels', [FilterType::HAS])->includeRelationFields()
        );
    }
}

class Label extends Model implements IsFilterable
{
    // ...
    public function allowedFilters(): AllowedFilterList
    {
        return Filter::only(
            Filter::field('labeled_by', [FilterType::EQUAL])
                ->pivot(Epic::class, Issue::class)
        );
    }
}
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport