matthenning/eloquent-api-filter

一种出色且简单的方法,通过API URL直接过滤Eloquent查询,无需杂乱无章。

v3.0.1 2024-01-22 13:56 UTC

README

Eloquent API Filter

一种出色且简单的方法,通过仅几行代码创建、查询和修改Eloquent模型,通过API实现。


概念

在开发API应用程序时,你可能会在控制器中遇到大量的重复代码。Eloquent API Filter通过定义一个路由和微小的控制器提供了一个简单的方法来通过API公开你的模型。你的控制器只需要使用几个特性,你将通过API公开你的模型获得完整的CRUD实现。


目录

安装

包安装

composer require matthenning/eloquent-api-filter

控制器设置

你可以选择以下方法之一来利用过滤功能。开箱即用的最简单方法是简单地扩展包含的控制器。

选项1:扩展控制器(推荐)

使用Eloquent API Filter的最简单方法是扩展其控制器。例如,假设你有一个名为Person的模型。你只需创建一个匹配的控制器并使用包含的特性来启用index、show、store、update、destroy的默认方法。

use Matthenning\EloquentApiFilter\Controller;

class PersonController extends Controller
{
    use UsesDefaultIndexMethodTrait,
        UsesDefaultShowMethodTrait,
        UsesDefaultStoreMethodTrait,
        UsesDefaultUpdateMethodTrait,
        UsesDefaultDestroyMethodTrait;

} 

接下来,你可以通过添加一个新的路由来公开你的控制器

Route::resource('persons', \App\Http\Controllers\PersonController::class);

Eloquent API Filter将自动找到匹配的模型类,只要你遵循此示例的命名约定。如果你有自定义名称或命名空间,你可以在控制器中覆盖modelName属性

protected ?string $modelName = Person::class;

完成!按照方法指南开始查询你的API。有关store、show、index、update、destroy操作,请参阅https://laravel.net.cn/docs/10.x/controllers#actions-handled-by-resource-controller

POST /api/persons
{
    "name": "Alexander",
    "age": 23
}

GET /api/persons/1

GET /api/persons/?filter[age]=23

PUT /api/persons/1
{
    "age": 24
}

DELETE /api/persons/1

自定义资源

如果你使用自定义资源(https://laravel.net.cn/docs/master/eloquent-resources),你可以在模型上定义resourceName属性。否则将使用默认资源。请确保覆盖toArray并调用enrich()来处理你的数据。enrich方法将确保所有预加载的关系(/model?with[]=relation1,relation2)也被它们各自资源转换。

在你的Person模型中

public static ?string $resourceName = PersonResource::class;

在你的PersonResource中

class PersonResource extends \Matthenning\EloquentApiFilter\Resource
{

    public function toArray(Request $request): array
    {
        return $this->enrich([
            'id' => $this->resource->id,
            // ... map your fields here
        ]);
    }

}

选项2:使用特性

如果你想要完全自己处理控制器和资源逻辑,可以在控制器中使用FiltersEloquentApi特性。

class PersonController extends Matthenning\EloquentApiFilter\Controller
{  
    
    use Matthenning\EloquentApiFilter\Traits\FiltersEloquentApi;
    
    public function index(Request $request)
    {
        $persons = Person::query();
        
        return $this->filterApiRequest($request, $persons);
    }
}

选项3:直接查询过滤

如果你不喜欢特性,你也可以自己初始化Eloquent API Filter。

use Matthenning\EloquentApiFilter\EloquentApiFilter;

class PersonController extends Controller
{    
    public function index(Request $request)
    {
        $query = Person::query();
        
        $filtered = (new EloquentApiFilter($request, $query))->filter();
        
        return $filtered->get();
    }
}


查询

过滤

URL语法

使用特定操作符进行过滤

GET /model?filter[field]=operator:comparison

过滤等于

GET /model?filter[field]=operator

操作符

  • eq(相等,可以省略)
  • ne(不等)
  • ge(大于或等于)
  • gt(大于)
  • le(小于或等于)
  • lt(小于)
  • in(期望以逗号分隔的数组作为值)
  • notin(期望以逗号分隔的数组作为值)
  • null
  • notnull
  • like
  • notlike
  • today(用于时间戳)
  • nottoday(用于时间戳)

示例

匹配所有以Rob开头且已故为null的实体

GET /persons?filter[name]=like:Rob*&filter[deceased]=null:

可以在一个字段上使用多个过滤器进行链式操作。匹配所有created_at在2016-12-10和2016-12-08之间的实体

GET /persons?filter[created_at]=lt:2016-12-10:and:gt:2016-12-08`

通过点符号使用相关模型的字段进行过滤。匹配所有包含"API"的Person的Posts

GET /persons?filter[posts.name]=like:*API*

获取所有名为Rob和Bob的人员

GET /persons?filter[name]=in:Rob,Bob

特殊过滤器

时间戳

匹配今天生日的人员

GET /persons?filter[birthday]=today

排序

URL语法

GET /model?orderBy[field]=direction

示例

限制和排序。匹配年龄为21岁或以上且按姓名升序排列的前10个人

GET /persons?filter[age]=ge:21&order[name]=asc&limit=10

选择字段

仅选择特定列。可能需要在模型转换上做额外工作。

URL语法

GET /model?select=column1,column2

示例

GET /persons?select=name,email

连接

URL语法

GET /model?with[]=relation1
GET /model?with[]=relation1&filter[relation1.field]=operator:comparison

示例

在人员上连接posts-relation

GET /persons?with[]=posts

复杂的过滤器值

如果您需要过滤包含特殊字符的值,可以将字段进行base64编码以避免破坏过滤器语法。

URL语法

GET /model?filter[field]={{b64(value)}}

示例

GET /model?filter[field]=lt:{{b64(MjAxNy0wNy0yMiAyMzo1OTo1OQ==)}}


响应

响应始终包含两个JSON对象:数据和元数据。数据包含查询的模型,而元数据包含例如分页详情。

示例

{
    "meta": {
        "pagination": {
            "items": 10,
            "total_items": 113,
            "total_pages": 12,
            "current_page": 1,
            "per_page": 10
        }
    },
    "data": [
        {
            "id": 1,
            "name": "Alexander",
            "age": 23
        },
        { /*...*/ }, { /*...*/ }
    ]
}


如果需要更多功能呢?

如果您需要复杂的查询,而这些查询超出了此库的范围,您可以在自定义控制器中使用EloquentApiFilter特质,并在检索模型之前进一步过滤查询。这样,您仍然可以使用过滤器功能,只需在返回检索到的模型之前添加自定义过滤即可。