aros/omnifetch-lumen

简化 fetch API 端点的 Lumen 获取库

v0.2.1 2022-03-11 10:45 UTC

This package is auto-updated.

Last update: 2024-09-11 16:30:56 UTC


README

OmniFetch for Lumen 是一个有用的库,它使 fetch API 端点更容易设置,并且足够灵活,适用于不同的情况。该库允许通过在请求中传递查询参数来动态修改响应数据集。这些修改可以包括应用过滤器、嵌入相关数据和分页,以及使用分组来聚合数据。

Total Downloads

安装

$ composer require aros/omnifetch-lumen

依赖关系

  • Lumen >= 5.5

主要功能

OmniFetch 只有两个方法可以使用。如下所示

  • OmniFetch::getSingle(Illuminate\Database\Eloquent\Builder $builder, array $params) - 用于获取单个记录。
  • OmniFetch::paginate(Illuminate\Database\Eloquent\Builder $builder, array $params) - 用于获取记录列表

所使用的构建器应使用模型(即主模型)创建。例如 Author::query()

参数选项

OmniFetch::getSingleOmniFetch::paginate 都需要其参数中的 $params,这是一个包含选项的关联数组。

  • filters(数据类型:JSON 列表/数组):向查询添加条件。它可以接受所需的所有条件。每个条件都是一个 JSON 对象(如果 filters 是一个 JSON 列表,则此格式最好如果作为请求查询参数传递),或一个关联数组(如果 filters 是一个数组)。它包含以下字段

    • field(必需):用于过滤的字段。它可以是主模型或相关模型(可以通过在主模型中指定的关系名称后面加上关系字段来实现。例如 *author.rating *)。它支持嵌套关系字段,例如 author.publisher.is_local
    • value(必需):要使用的值。

    注意:如果值中使用 %,则如果作为请求查询参数传递,则需要对其进行 URL 编码。

    • cond_op(可选 | 默认:'='):比较字段和值时使用的条件运算符。可用的运算符包括:=,!=,>,<,>=,<=,LIKE,IS_NULL(仅需要 field),IS_NOT_NULL(仅需要 field)。
    • logical_op(可选 | 默认:'AND'):在它之后结合剩余过滤器的逻辑运算符。可用的运算符包括 AND 和 OR。

    示例:

    • [{"field": "status_id", "value": 1}] => ... WHERE primary_table.status_id = 1;
    • [{"field": "name", "value": "%25rich%25", "cond_op": "LIKE"}] => ... WHERE primary_table.name LIKE "%rich%";
    • [{"field": "status_id", "value": 1}, {"field": "author.rating", "value": 2.5, "cond_op": ">="}] => ... WHERE primary_table.status_id = 1 AND author.rating >= 2.5
    • [{"field": "likes", "value": 100, "cond_op": ">", "logical_op": "OR"}, {"field": "rating", "value": 4.0, "cond_op": ">="}, {"field": "rating", "value": 4.5, "cond_op": "<="}] => ... WHERE primary_table.like > 100 OR (primary_table.rating >= 4.0 AND primary_table.rating <= 4.5)
  • embeds(数据类型:JSON 列表/数组):将相关模型数据嵌入到正在获取的主模型中。仅允许主模型的关联关系名称及其关联关系(这意味着允许嵌套关系)。

    示例 :

    • ["status", "author.publisher"]
  • no_pages(数据类型:布尔值 | 默认为 false):指定是否分页。

  • page(数据类型:整数 | 默认:1):指定分页时的当前页。

  • page_size (数据类型:整数 | 默认:20):指定分页时每页返回的记录数

  • order_by (数据类型:字符串):指定排序的字段(目前不支持关联字段)。

  • is_asc (数据类型:布尔值 | 默认:true):指定排序方向

  • aggs (数据类型:JSON列表/数组):用于执行求和最小值最大值等聚合操作。列表中指定的每个聚合都是一个JSON对象(如果aggs是一个JSON列表)或关联数组(如果aggs是一个数组)。以下是可以用于每个聚合的字段

    • field (必需):要聚合的字段。这可以是关联字段的字段。允许嵌套关联。

      注意:为了使用关联字段,主模型必须具有OmniFetch\HasJoinWith特征。

    • alias (必需):用于聚合的别名。

    • func (必需):聚合函数。以下是可以用的函数

      • count => COUNT({{col}})
      • avg => AVG({{col}})
      • min => MIN({{col}})
      • max => MAX({{col}})
      • sum => SUM({{col}})

    示例:

    • [{"field": "likes", "func": "sum", "alias": "total_likes"}] => SELECT SUM(primary_table.likes) AS total_likes ...
  • group_by (数据类型:JSON列表/数组):用于分组数据。每个分组列由一个JSON对象表示(如果group_by是一个JSON列表)或关联数组(如果group_by是一个数组)。以下是可以用于每个分组的字段

    • field (必需):用于分组的字段。这可以是关联字段的字段。允许嵌套关联。

      注意:要使用关联字段,主模型必须具有OmniFetch\HasJoinWith特征。

    • func (可选):分组函数。以下是可以用的函数

      • date => DATE({{col}})
      • month => DATE_FORMAT({{col}}, '%Y-%m')
      • year => YEAR({{col}})
    • alias (如果使用func则为必需):用于分组的别名。

    示例:

    • [{"field": "created_at", "func": "date", "alias": "created_date"}] => ... GROUP BY DATE(primary_table.created_at) AS created_date

用法

可以通过一个例子来说明。在这个例子中,创建了getOnePostgetAllPosts端点。使用的模型(或实体)是

  • Publisher:一家雇佣作者撰写帖子的公司。
  • Author:撰写帖子并属于publisher的人。
  • Post:由作者撰写的内容

在这个例子中,Post是主模型,而AuthorPublisher是相关模型。

注意:为了使库非常有效,模型关系应该设置良好

首先,让我们设置模型(假设已完成数据库迁移和其他项目先决条件)

出版商模型

<?php  
  
namespace App\Models;  

use Illuminate\Database\Eloquent\Model;  
  
/**  
 * Class Publisher 
 * @package App\Models
 *   
 * @property integer $id  
 * @property string $name  
 * @property string $address  
 * @property boolean $is_local  
 * @property string $created_at  
 * @property string $modified_at  
 * @property integer $status_id  
 */
class Publisher extends Model  
{  
  protected $table = 'publishers';  
  public $timestamps = false;  
}

作者模型

<?php  
  
namespace App\Models;  
  
use Illuminate\Database\Eloquent\Model;  
use Illuminate\Database\Eloquent\Relations\BelongsTo;  
  
/**  
 * Class Author 
 * @package App\Models
 *   
 * @property integer $id  
 * @property integer $publisher_id  
 * @property string $first_name  
 * @property string $last_name  
 * @property float $rating  
 * @property string $created_at  
 * @property string $modified_at  
 * @property integer $status_id  
 */
class Author extends Model  
{  
  protected $table = 'authors';  
  public $timestamps = false;  
  
  /**  
  * @return BelongsTo  
  */  
  public function publisher()  
  {  
    return $this->belongsTo(Publisher::class, 'publisher_id');  
  }  
}

帖子模型

<?php  
  
namespace App\Models;  
  
use Illuminate\Database\Eloquent\Model;  
use Illuminate\Database\Eloquent\Relations\BelongsTo;  
use OmniFetch\HasJoinWith;  
  
/**  
 * Class Post 
 * @package App\Models  
 * 
 * @property integer $id  
 * @property integer $author_id  
 * @property string $title  
 * @property string $content  
 * @property float $rating  
 * @property integer $likes  
 * @property string $created_at  
 * @property string $modified_at  
 * @property integer status_id  
 */
class Post extends Model  
{  
  use HasJoinWith;  
  
  protected $table = 'posts';  
  public $timestamps = false;  
  
  /**  
  * @return BelongsTo  
  */  
  public function author()  
  {  
    return $this->belongsTo(Author::class, 'author_id');  
  } 
}

其次,让我们设置控制器

<?php  
  
namespace App\Http\Controllers;  
  
use App\Models\Post;  
use Illuminate\Http\Request;  
use OmniFetch\OmniFetch;  
  
class ExampleController extends Controller  
{  
  public function fetchAllPosts(Request $request)  
  {  
    $data = (new OmniFetch())->paginate(Post::query(), $request->query());  
    return response()->json($data);  
  }  
  
  public function fetchOnePost(Request $request, $post_id)  
  {  
    $post = (new OmniFetch())->getSingle(Post::where('id', $post_id), $request->query());  
    return response()->json($post->toArray());  
  }  
}

最后,添加路由(我们完成了!)

<?php
// routes/web.php

$router->get('/posts', ['uses' => 'ExampleController@fetchAllPosts']);  
$router->get('/posts/{post_id}', ['uses' => 'ExampleController@fetchOnePost']);

带有响应的请求示例

  • GET {{base_url}}/posts/1?embeds=["author"]

    响应

    点击以显示响应

     {
         "id": 1,
         "author_id": 101,
         "title": "Quis ut exercitationem nihil nemo quos aut numquam doloribus.",
         "content": "Nisi rerum harum reprehenderit. Rem commodi non dolorum repellendus. Quibusdam nobis voluptatibus illum alias voluptatem. Earum dolorem aspernatur quia sint.",
         "rating": 0.48,
         "likes": 95,
         "created_at": "1980-01-18 18:52:07",
         "modified_at": "1994-02-01 18:58:16",
         "status_id": 1,
         "author": {
             "id": 101,
             "publisher_id": 26,
             "first_name": "Mellie",
             "last_name": "Casper",
             "rating": 2.47,
             "created_at": "1995-02-14 08:41:00",
             "modified_at": "1985-10-23 13:17:36",
             "status_id": 1
         }
     }

  • GET {{base_url}}/posts?page=3&page_size=2&filters=[{"field": "author.rating", "value": 3.5, "cond_op": ">"}]&embeds=["author.publisher"]&order_by=likes&is_asc=0

    响应

    点击以显示响应

     {
         "pagination": {
             "total_count": 142,
             "total_pages": 71,
             "current_page": 3,
             "count": 2
         },
         "list": [
             {
                 "id": 325,
                 "author_id": 220,
                 "title": "Tempore aperiam eum itaque voluptates illo dolor.",
                 "content": "Qui nemo delectus iste sequi voluptates impedit beatae. Accusamus eligendi qui tenetur voluptatum maxime. Sapiente blanditiis omnis deserunt suscipit voluptates.",
                 "rating": 1.19,
                 "likes": 2440,
                 "created_at": "2019-04-06 12:32:59",
                 "modified_at": "2019-05-27 11:15:37",
                 "status_id": 1,
                 "author": {
                     "id": 220,
                     "publisher_id": 73,
                     "first_name": "Serena",
                     "last_name": "Bernier",
                     "rating": 4.58,
                     "created_at": "2012-06-21 11:27:25",
                     "modified_at": "2012-06-21 12:36:46",
                     "status_id": 1,
                     "publisher": {
                         "id": 73,
                         "name": "Prosacco-Lueilwitz",
                         "address": "126 Clarissa Wells West Blanca, WY 11801",
                         "is_local": 0,
                         "created_at": "2001-04-01 08:02:02",
                         "modified_at": "2001-04-01 08:02:02",
                         "status_id": 1
                     }
                 }
             },
             {
                 "id": 204,
                 "author_id": 235,
                 "title": "Officia est in exercitationem veniam libero quo sed.",
                 "content": "Commodi tempore a harum aut magni. Ad harum natus minima eos amet. Doloribus sequi veritatis voluptatem sint voluptates deleniti. Id et explicabo et dolores exercitationem et nam.",
                 "rating": 0.67,
                 "likes": 2435,
                 "created_at": "2019-11-05 13:02:07",
                 "modified_at": "2019-11-30 07:38:01",
                 "status_id": 1,
                 "author": {
                     "id": 235,
                     "publisher_id": 91,
                     "first_name": "Alexzander",
                     "last_name": "Kemmer",
                     "rating": 4.64,
                     "created_at": "2001-09-07 23:24:12",
                     "modified_at": "2001-09-07 23:24:12",
                     "status_id": 1,
                     "publisher": {
                         "id": 91,
                         "name": "Smitham LLC",
                         "address": "029 Pierre Greens Apt. 445 South Mallory, SC 88096",
                         "is_local": 1,
                         "created_at": "1995-08-15 21:46:30",
                         "modified_at": "1995-08-15 21:46:30",
                         "status_id": 1
                     }
                 }
             }
         ]
     }

  • GET {{base_url}}/posts?aggs=[{"field": "author.rating", "func": "avg", "alias": "average_rating"}]&group_by=[{"field": "author.publisher.name", "alias": "publisher_name"}]&page_size=3

    注意:当使用aggsgroup_by时,限制返回的字段为aggsgroup_by字段

    响应

    点击以显示响应

     {
         "pagination": {
             "total_count": 89,
             "total_pages": 30,
             "current_page": 1,
             "count": 3
         },
         "list": [
             {
                 "publisher_name": "Ankunding Ltd",
                 "average_rating": 1.6022222108311
             },
             {
                 "publisher_name": "Bashirian-Altenwerth",
                 "average_rating": 3.2622222635481
             },
             {
                 "publisher_name": "Baumbach Ltd",
                 "average_rating": 3.0066666603088
             }
         ]
     }