mdantas/express-request

CakePHP 的 ExpressRequest 插件

安装次数: 118

依赖项: 0

建议者: 0

安全: 0

星级: 2

关注者: 3

分支: 1

开放问题: 0

类型:cakephp-plugin

v2.1.9 2022-07-09 13:21 UTC

This package is auto-updated.

Last update: 2024-09-09 18:04:22 UTC


README

关于此包的一些内容

这个包在查询 URL 方面帮助我很多,也许它也会帮到你。我经常在尝试制作 API 时,试图制作复杂的 URL 和查询字符串参数,我感到很沮丧,因为有些东西没有意义。在 poc 和 poc 以及好伴侣的帮助下,我得出以下结论。

这个包如何帮助你

与其制作越来越复杂的 URL 查询参数或许多端点,不如尝试制作真正适合客户的需求模型,进入代码。

安装

您可以使用 composer 将此插件安装到您的 CakePHP 应用程序中。

安装 composer 包的推荐方法是

composer require mdantas/express-request

将插件添加到我们的 Application.php

public function bootstrap(): void
{
    //... other codes.
    $this->addPlugin('ExpressRequest');
}

在模型上表达过滤条件

我们的表对象需要实现 ExpressRepositoryInterface 并创建新方法。

//Model/Table/DomainsTable.php
class DomainsTable extends Table implements ExpressRepositoryInterface {
    //...code...
    
    public function getFilterable(): FiltersCollection
    {
        return new FiltersCollection([
            new BooleanFilter('active'),
            new SearchFilter('name', SearchFilter::START_STRATEGY),
            new SearchDateFilter('created_at'),
            new NumberFilter('price'),
            new SearchInFilter('type')
        ]);
    }

    public function getSelectables(): array
    {
        return [
            'name',
            'created_at',
            'price',
            'type',
            'active'
        ];
    }
}

控制器

Controller/AppController.php 中加载名为: ExpressRequest.ExpressParams 的组件,现在,向我们的 DomainsController 添加一些代码。

//Controller/DomainsController.php

public function index()
{
    // The finder need to be a method what return a Cake\ORM\Query object.
    return $this
        ->responseJson(
            $this->ExpressRequest->search(
                $this->request,
                $this->Domains,
                'findDomainsByCompany', // Finder model method optional
                $companyId // Optional
            )
        );
}

public function anotherWay() {
   // We can make our filtering by request expressions
   $collection = $this->ExpressRequest->search(
                $this->request,
                $this->Domains
            );
            
   $query = $collection->getQuery();

   // And can implement our needed things above user api expressions.
   $query->where(['id' => 1]);
   return $this->responseJson($collection);
}

public function alternative()
{
    // Request and Model now is taked from controller.
    // Need status code
    // Return a ResponseInterface from psr with json data on body.
    return this->ExpressRequest->getResponse(200);
}

*当然,别忘了为这个控制器添加路由。

//routes.php
$routes->scope('/', function (RouteBuilder $builder) {
    $builder->get('/domains', ['controller' => 'Domains', 'action' => 'index']);
}

请求

让我们看看您的 /domains 端点现在对请求/资源更友好。

在浏览器中打开: https://:8765/domains?price=140..3000&sort[price]=asc&type[not]=profit&size=1

// https://:8765/domains?price=140..3000&sort[price]=asc&type[not]=profit&size=1

{
  "data": [
    {
      "id": "dee7b40b-df70-33b7-90e0-1d13a4b13693",
      "name": "Azevedo e Pacheco",
      "company_id": "2130a414-828a-4ae3-a3a6-5f153fe25ad8",
      "city_id": 2507705,
      "created_at": "2010-02-12T21:18:44+00:00",
      "modified_at": null,
      "price": "291.600",
      "type": "purchase"
    }
  ],
  "meta": {
    "total": 103,
    "per_page": 1,
    "current_page": 1,
    "last_page": 103,
    "first_page_url": "https://:8765/domains?price=140..3000&sort%5Bprice%5D=asc&type%5Bnot%5D=profit&size=1&page=1",
    "next_page_url": "https://:8765/domains?price=140..3000&sort%5Bprice%5D=asc&type%5Bnot%5D=profit&size=1&page=2",
    "last_page_url": "https://:8765/domains?price=140..3000&sort%5Bprice%5D=asc&type%5Bnot%5D=profit&size=1&page=103",
    "prev_page_url": null,
    "path": "https://:8765/domains",
    "from": 1,
    "to": 1
  }
}

详细信息

我刚才提到这个帮助了我很多,现在,看看这些内容是如何工作的。

每个请求都在 ExpressRequest.ExpressParams 上进行处理。该组件试图理解请求需要什么,并借助模型生成响应、一些操作或用户可以引入的简单请求错误。因为请求错误,所以模型向组件表达它能做什么,如果它不能,则不会发生任何事情。想想看,如果我们尝试在布尔类型的数据中搜索 'A' 会怎样?因此,实现了一些类型过滤。

仅选择字段。

// localhost/domains?props=name,price,created_at - Select only this three fields.

数据排序

对于每个字段,有两个值:asc,desc。

// localhost/domains?sort[name]=asc
// localhost/domains?sort[name]=asc&sort[price]=desc

包含数据

有时我们需要检索具有关联的数据,当然,这很容易。

// https://:8765/domains?nested=users,comments //Get data with relationship

需要向相关数据添加复杂或条件,简单的答案是:您不能,也不应该尝试。如果您需要一些复杂的相关数据,请参阅:CakePHP 文档

过滤器

强大且安全的过滤器

布尔过滤器

通过布尔值进行过滤?例如 'true', 'false', '1', '0'

数字过滤器

可以通过一些帮助过滤数据。

// localhost/domains?price=100 - Exact by 100
// localhost/domains?price=100..200 - Between 100 and 200
// localhost/domains?price[lt|gt|lte|gte]=100 - filter less, great, less than or great than.
空值过滤器

此过滤器简单地执行查询中的 is 或 is not null。

new SearchFilter('name')
// localhost/domains?name=null - WHERE name IS NULL
// localhost/domains?name[is]=null - WHERE name IS NULL
// localhost/domains?name[not]=null - WHERE name IS NOT NULL
搜索过滤器

此过滤器有四种工作方法

class SearchFilter implements FilterTypeInterface
{
    use ProcessableFilterTrait;

    const PARTIAL_STRATEGY = 'partial';
    const START_STRATEGY = 'start';
    const END_STRATEGY = 'end';
    const EXACT_STRATEGY = 'exact';
    
    ...code
}
new SearchFilter('name') - Exact is default
// localhost/domains?name=marcos - Exact by marcos
new SearchFilter('name', SearchFilter::PARTIAL_STRATEGY)
// localhost/domains?name=marcos - add a %value% by like method.
new SearchFilter('name', SearchFilter::START_STRATEGY) 
// localhost/domains?name=marcos - add a value% by like method.
new SearchFilter('name', SearchFilter::END_STRATEGY) 
// localhost/domains?name=marcos - add a %value by like method.
搜索过滤器

通过值或组值进行过滤。

// localhost/domains?name=marcos - name in('marcos')
// localhost/domains?name=marcos,github - name in('marcos', 'github')
// localhost/domains?name[not]=marcos,github - name not in('marcos', 'github') 
日期搜索过滤器

2.0.1 可以使用 [gte, gt, lt, lte] 操作符。

// localhost/domains?created_at=2019 - by init of 2019 year.
// localhost/domains?created_at=2019-01 - by init of Jan/2019 year.
// localhost/domains?created_at=201903 - by init of Mar/2019 year.
// localhost/domains?created_at=2019-01-12 - by day 12 of Jan/2019 year.
// localhost/domains?created_at=20190315 - by day 15 of Mar/2019 year.
// localhost/domains?created_at[lte]=20190315 - search by operators: [lt, lte, gt, gte]
// localhost/domains?created_at[lte]=20190315&created_at[gte]=20190315 - search by operators: [lt, lte, gt, gte]
自定义过滤器?

通过实现 FilterTypeInterface 并如果您想要 ProcessableFilterTrait,您可以为所需的内容创建一个过滤器。

关于组件

组件有一系列配置值,用于处理查询参数,如果没有 reserved 键,则尝试过滤内容,如果模型接受它,则执行 URL 查询

[
    'pagination' => true,
    'maxSize' => 100, // Max number of per page.
    'size' => 20, // default numbers of items per page
    'ssl' => true, // generate routes with ssl by default,
    'cacheConfig' => 'default', // cache config
    'cache' => true, // Enable or disable cache
    'reserved' => [  // If you need to use one o more of this keywords, change to alias.
        'size' => 'size',
        'page' => 'page',
        'props' => 'props',
        'nested' => 'nested',
        'sort' => 'sort'
    ]
];

更改一些配置...

//Controller/AppController.php
public function initialize()
{
    // ...code
    $this->loadComponent('ExpressRequest.ExpressRequest', [
        'ssl' => false,
        'maxSize' => 30,
        'reserved' => [
            'props' => 'fields'
        ]
    ]);
}