fh/laravel-prefix-api-query-builder

Laravel基于API标准URI与构建对象之间的翻译。


README

API查询字符串与Eloquent构建器之间的一种简单、可单元测试的转换设备。

它很简单。QueryBuilder接收一个Illuminate\Http\Request对象(或FormRequest)并转换为如下URI字符串

/api/v1/companies/48/contacts?likeFirstName=Johnny&betweenStatus[]=4&betweenStatus[]=8

变为

<?php
$model->where('ParentId','=',48)
      ->where('FirstName','LIKE','%Johnny%')
      ->whereBetween('Status',4,8);

特性

  • 支持嵌套关系,内在地限制结果为父对象拥有的子集,这些子集根据在Eloquent模型中定义的关系。
  • 支持所有常见的SQL比较运算符
    • IS NULL
    • IS NOT NULL
    • WHERE
    • OR WHERE
    • WHERE LIKE
    • OR WHERE LIKE
    • BETWEEN
    • IN ()
    • NOT IN ()
    • 以及所有标准运算符:=, >, <, <=, >=。
  • 支持ORDER BY和GROUP BY。
  • 支持按子关系对父关系进行排序,例如:SELECT o.* FROM organizations o JOIN projects p ON o.OrgId = p.OrgId ORDER BY p.Date
  • 支持Laravel作用域。
  • 支持在查询前缀后搜索子关系,格式为relationname.FieldName=value。
  • 支持预加载关系:$model->with(...)
  • 支持多种分页模式,包括limit/offset和page=X。
  • 可以自定义分页参数名称。
  • 完全单元测试,每个场景都有广泛的测试用例。
  • 可扩展。扩展Fh\QueryBuilder以添加您自己的新运算符和子句类型,或向现有功能添加自定义行为。
  • 开源。MIT许可证。

安装

$> composer require fh/laravel-prefix-api-querybuilder

用法

配置

以下是配置文件,应将其存储在您的应用程序的config/文件夹中,文件名为:fh-laravel-api-query-builder.php。请阅读注释以获取有关每个配置变量及其功能的详细信息。

<?php
return [
    /**
     * This is the route prefix that your API might use
     * before starting the route to any single resource.
     */
    'baseUri' => '/api/v1/',

    // Default page limit while doing pagination.
    'defaultLimit' => 10,

    /**
     * Model namespace
     *
     * This is the namespace that your models will be prefixed with
     * when they are found in the route to model mapping that you
     * provide to the QueryBuilder when you instantiate it.
     *
     * You can leave this blank, and simply provide the full class path
     * of your models directly in the mapping if you want to.
     */
    'modelNamespace' => 'Fh\QueryBuilder',

    /**
     * Paging Style
     * Two different types of paging styles are supported:
     * 'page=' and 'limit/offset'
     *
     * The 'page=' style is like laravel's default paging
     * style, except that you can control the name of the paging
     * parameter. This is helpful for backward compatability with
     * older API signatures.
     *
     * The 'limit/offset' style is just that. Instead of specifying
     * a page number and a number of results per page, you specify
     * a limit and an offset, much like what MySQL developers are
     * familiar with in a SQL query.
     */
    'pagingStyle' => 'limit/offset',

    /**
     * Name of offset/limit/page parameters used as described
     * above 'pagingStyle'.
     */
    'offsetParameterName' => 'offset',
    'limitParameterName'  => 'limit',
    'pageParameterName'   => 'page'
];

服务提供商设置

将以下服务提供商添加到您的config/app.php文件中

Fh\QueryBuilder\FhApiQueryBuilderServiceProvider::class

实现

查询构建器旨在在Laravel控制器中使用,该控制器定义了两件事

  • 路由到模型的映射,因此路由名称和模型名称可以分开
  • Illuminate\Http\Request对象的一个实例(或FormRequest,因为它是前者的子类)。

以下是一个示例控制器,以帮助您开始。代码中的注释同样有用。

<?php

namespace App\Http\Controllers;

use App\Http\Requests;
use Illuminate\Http\Request;
use Fh\QueryBuilder\QueryBuilder;

/**
 * ApiController for routing all queries to a database.
 * This follows the laravel resource controller interface.
 * Use this as a base class for other resource controllers
 * So you can customize other parts of this resource controller.
 */
class RestApiController extends Controller {

    protected $routeMap = [
        'organizations'          => 'Organization',
        'organizations.contacts' => 'Organization.contacts'
    ];

    public function index(Request $request) {
        // Instantiate the builder
        $qb = new QueryBuilder($this->routeMap,$request);
        // Apply all URI parameters
        $qb->build();

        // If you're using limit/offset paging, you can get the total
        // number of records manually.
        $iTotalRecordCount = $qb->getCount();
        $results = $qb->paginate();

        // Otherwise, you can use Laravel's LengthAwarePaginator
        // that comes with Laravel 5
        $paginator = $qb->paginate();
    }

}

参数前缀参考

参数前缀调用的构建器方法默认运算符注释
isnullwhereNullNA
isnotnullwhereNotNullNA
orwhereorWhere=
wherewhere=
orderbyorderByNA
groupbygroupByNA
betweenwhereBetweenNA
notinarraywhereNotInNA
inarraywhereInNA
likewhereLIKE传递的值会自动用%%包裹,以便于使用。因此,您不需要在查询字符串中包含百分号。
orlikeorWhereLIKE传递的值会自动用%%包裹,以便于使用。因此,您不需要在查询字符串中包含百分号。
greaterthanwhere>
greaterthanorequaltowhere>=
lessthanwhere<
lessthanorequaltowhere<=

示例

无嵌套关系的简单查询

/api/v1/organizations?with[]=contacts&inarrayCountry[]=Guatemala&inarrayCountry[]=USA

变为

$builder = $organization->with('contacts')
               ->whereIn('Country',['Guatemala','USA']);

嵌套关系的简单示例

/api/v1/organizations/2061/contacts

变为

$org = $organization->find(2061);
$builder = $org->contacts();

带有works的嵌套关系

/api/v1/letters/23/photos?with[]=translations&with[]=original&isnullCaption&isnotnullOriginalId&likeFirstName=Jon&filterAppropriateForPrint&lessthanTestId=25

变为

$l = $letter->find(23);
$builder = $l->photos()
      ->appropriateForPrint() // This is a scope call
      ->with(['translations','original'])
      ->whereNull('Caption')
      ->whereNotNull('OriginalId')
      ->where('FirstName','LIKE','%Jon%')
      ->where('TestId','<',25)

通过子关系中的值返回一组记录

/api/v1/letters/23/organizations?likecontacts.FirstName=Jon

变为

$builder = $organization->whereHas('contacts', function($q) {
    $q->where('FirstName','LIKE','%Jon%');
});

通过ID返回单个记录,并包含一些预加载的关系

/api/v1/organizations/23?with[]=contacts&with[]=notes

变为

$builder = $letter->with('contacts','notes')
                  ->where($primaryKey,'=',23);

按特定字段排序的结果列表

/api/v1/organizations/23?orderbyLastName

变为

$builder = $letter->orderBy('LastName');

按关系字段排序的结果列表。

/api/v1/organizations/23?sortbychildcontact.CreationDate=asc

变为

$builder = $letter->join("Contact AS relTable","relTable.LetterId",'=',"Letter.LetterId")
                  ->orderBy("Contact.CreationDate",'asc')
                  ->select("Letter.*");

贡献

我很乐意考虑您想提交的任何拉取请求。建设性的评论也始终受欢迎。

许可证

MIT许可证