承接 denmarty/marty-query-filter 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

denmarty/marty-query-filter

Composer 安装命令:

composer require denmarty/marty-query-filter

包简介

Reusable query filter pipeline for Laravel Eloquent builders.

README 文档

README

Reusable query filter pipeline for Laravel Eloquent builders.

Features

  • simple QueryFilter contract for custom filters
  • FilterPipeline with Laravel container resolution
  • built-in search filter
  • relation-aware filters through whereHas(...)
  • normalized filter keys through Str::snake(...)
  • support for inline filter configuration and legacy parameter registry

Requirements

  • PHP 8.2+
  • Laravel 11 or 12

Installation

composer require denmarty/marty-query-filter

Laravel package discovery is supported automatically.

Core idea

You register allowed filters once, then pass request data into the pipeline.

Each filter:

  • has a public input key such as status, auction_name, year_of_release
  • points to a class that implements QueryFilter
  • can optionally receive extra constructor parameters
  • can optionally be applied inside a relation

QueryFilter contract

Every custom filter must implement Denmarty\MartyQueryFilter\QueryFilter.

<?php

namespace App\QueryFilters;

use Denmarty\MartyQueryFilter\QueryFilter;
use Illuminate\Database\Eloquent\Builder;

final class StatusFilter implements QueryFilter
{
    public function apply(Builder $query, mixed $value): Builder
    {
        if ($value === null || $value === '') {
            return $query;
        }

        return $query->where(
            column: 'status',
            operator: '=',
            value: $value,
        );
    }
}

Basic usage

<?php

use App\Models\Post;
use App\QueryFilters\StatusFilter;
use Denmarty\MartyQueryFilter\FilterPipeline;

$filters = new FilterPipeline(
    filters: [
        'status' => [
            'filter' => StatusFilter::class,
        ],
    ],
);

$fields = [
    'status' => 'published',
];

$query = $filters->apply(
    query: Post::query(),
    fields: $fields,
);

Preferred filter configuration format

The recommended format is to declare every filter as a configuration array:

<?php

use App\QueryFilters\AuctionNameFilter;
use App\QueryFilters\MileageFilter;
use App\QueryFilters\YearOfReleaseFilter;
use Denmarty\MartyQueryFilter\FilterPipeline;

$filters = new FilterPipeline(
    filters: [
        'mileage' => [
            'filter' => MileageFilter::class,
        ],
        'auction_name' => [
            'filter' => AuctionNameFilter::class,
            'relation' => 'libAuctionName',
        ],
        'year_of_release' => [
            'filter' => YearOfReleaseFilter::class,
        ],
    ],
);

This format is explicit and keeps all filter metadata in one place.

Supported constructor arguments

FilterPipeline constructor accepts these named arguments:

  • filters
  • filterParameters
  • search

1. filters

Main filter registry.

Each filter must be declared as a configuration array with the filter key:

<?php

use App\QueryFilters\StatusFilter;
use Denmarty\MartyQueryFilter\FilterPipeline;

$filters = new FilterPipeline(
    filters: [
        'status' => [
            'filter' => StatusFilter::class,
        ],
    ],
);

Or with a relation:

<?php

use App\QueryFilters\AuctionNameFilter;
use Denmarty\MartyQueryFilter\FilterPipeline;

$filters = new FilterPipeline(
    filters: [
        'auction_name' => [
            'filter' => AuctionNameFilter::class,
            'relation' => 'libAuctionName',
        ],
    ],
);

2. filterParameters

Legacy-compatible parameter registry. Still supported.

Use it when you want to keep filter class registration separate from extra parameters:

<?php

use App\QueryFilters\AuctionNameFilter;
use Denmarty\MartyQueryFilter\FilterPipeline;

$filters = new FilterPipeline(
    filters: [
        'auction_name' => [
            'filter' => AuctionNameFilter::class,
        ],
    ],
    filterParameters: [
        'auction_name' => [
            'relation' => 'libAuctionName',
        ],
    ],
);

3. search

Shortcut for configuring the built-in search filter directly in the constructor.

<?php

use App\QueryFilters\StatusFilter;
use Denmarty\MartyQueryFilter\FilterPipeline;

$filters = new FilterPipeline(
    filters: [
        'status' => [
            'filter' => StatusFilter::class,
        ],
    ],
    search: [
        'fields' => ['title', 'slug'],
        'relations' => [
            'author' => ['name'],
            'category' => ['name'],
        ],
    ],
);

Aliases are also supported:

  • search_fields -> fields
  • search_relations -> relations

Example:

<?php

use App\QueryFilters\StatusFilter;
use Denmarty\MartyQueryFilter\FilterPipeline;

$filters = new FilterPipeline(
    filters: [
        'status' => [
            'filter' => StatusFilter::class,
        ],
    ],
    search: [
        'search_relations' => [
            'author' => ['name'],
        ],
    ],
);

Full example

<?php

use App\Models\Post;
use App\QueryFilters\AuthorNameFilter;
use App\QueryFilters\PublishedFilter;
use App\QueryFilters\StatusFilter;
use Denmarty\MartyQueryFilter\FilterPipeline;

$filters = new FilterPipeline(
    filters: [
        'status' => [
            'filter' => StatusFilter::class,
        ],
        'published' => [
            'filter' => PublishedFilter::class,
        ],
        'author_name' => [
            'filter' => AuthorNameFilter::class,
            'relation' => 'author',
        ],
    ],
    search: [
        'fields' => ['title', 'slug'],
        'relations' => [
            'author' => ['name'],
            'category' => ['name'],
        ],
    ],
);

$fields = [
    'status' => 'published',
    'author_name' => 'Denis',
    'search' => 'Laravel',
];

$query = $filters->apply(
    query: Post::query(),
    fields: $fields,
);

Relation-aware filters

If a filter configuration contains relation, the pipeline applies that filter through whereHas(...).

<?php

use App\QueryFilters\AuctionNameFilter;
use Denmarty\MartyQueryFilter\FilterPipeline;

$filters = new FilterPipeline(
    filters: [
        'auction_name' => [
            'filter' => AuctionNameFilter::class,
            'relation' => 'libAuctionName',
        ],
    ],
);

This produces logic equivalent to:

<?php

use App\QueryFilters\AuctionNameFilter;
use Illuminate\Database\Eloquent\Builder;

$query->whereHas('libAuctionName', function (Builder $relationQuery) use ($value): void {
    (new AuctionNameFilter())->apply(
        query: $relationQuery,
        value: $value,
    );
});

Inside the filter, you work with the relation query builder, not the root model query.

Built-in search filter

FilterPipeline automatically registers search.

That means you do not need to add search => SearchFilter::class manually.

Supported search configuration:

<?php

use App\QueryFilters\StatusFilter;
use Denmarty\MartyQueryFilter\FilterPipeline;

$filters = new FilterPipeline(
    filters: [
        'status' => [
            'filter' => StatusFilter::class,
        ],
    ],
    search: [
        'fields' => ['title', 'slug'],
        'relations' => [
            'author' => ['name'],
            'author.profile' => ['first_name', 'last_name'],
            'category' => ['name'],
        ],
    ],
);

Search behavior

  • empty search value is ignored
  • if both fields and relations are empty, search is ignored
  • relation search uses orWhereHas(...)
  • relation entries with an empty field list are skipped

Important SQL note

The built-in SearchFilter uses ilike:

<?php

$query->where(
    column: 'column',
    operator: 'ilike',
    value: '%term%',
);

This is appropriate for PostgreSQL.

If your project uses MySQL or another database that does not support ilike, create your own search filter or override the package behavior for that project.

Container resolution

Filters are resolved through the Laravel container:

  • app()->make(...)
  • app()->makeWith(...)

So constructor injection is supported.

<?php

namespace App\QueryFilters;

use Denmarty\MartyQueryFilter\QueryFilter;
use Illuminate\Database\Eloquent\Builder;

final class VisibilityFilter implements QueryFilter
{
    public function __construct(
        private readonly string $column = 'visibility',
    ) {}

    public function apply(Builder $query, mixed $value): Builder
    {
        return $query->where(
            column: $this->column,
            operator: '=',
            value: $value,
        );
    }
}

Filter key normalization

Filter keys are normalized with Str::snake(...).

That means these keys resolve to the same filter:

  • auction_name
  • AuctionName
  • auctionName

Because of that, duplicate normalized keys are not allowed.

Validation rules enforced by the pipeline

The pipeline throws InvalidArgumentException when:

  • a filter key is empty
  • the same normalized filter key is registered twice
  • a filter class does not exist
  • a filter class does not implement QueryFilter
  • inline filter configuration does not contain a valid filter key
  • relation is present but not a non-empty string
  • filterParameters contains a key that is not registered in filters

Unknown input keys

Unknown keys from request input are ignored.

<?php

use App\Models\Post;
use App\QueryFilters\StatusFilter;
use Denmarty\MartyQueryFilter\FilterPipeline;

$pipeline = new FilterPipeline(
    filters: [
        'status' => [
            'filter' => StatusFilter::class,
        ],
    ],
);

$query = $pipeline->apply(
    query: Post::query(),
    fields: [
        'status' => 'published',
        'unknown_filter' => 'value',
    ],
);

Only status will be applied.

Package structure

  • src/QueryFilter.php - filter contract
  • src/FilterPipeline.php - registry, validation, execution
  • src/SearchFilter.php - built-in text search filter

Testing

composer test

Formatting

composer lint

License

MIT

denmarty/marty-query-filter 适用场景与选型建议

denmarty/marty-query-filter 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 187 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 05 月 01 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「laravel」 「filters」 「pipeline」 「eloquent」 「query-filters」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 denmarty/marty-query-filter 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 denmarty/marty-query-filter 我们能提供哪些服务?
定制开发 / 二次开发

基于 denmarty/marty-query-filter 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 187
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 7
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-05-01