weapnl/laravel-junction

轻松创建具有扩展功能的REST API,例如预加载、搜索、筛选等。

v0.1.1 2024-09-09 12:59 UTC

This package is auto-updated.

Last update: 2024-09-09 13:01:05 UTC


README

此项目允许您轻松使用Laravel创建REST API。它具有扩展功能,例如预加载、搜索、筛选等。

目录

安装

composer require weapnl/laravel-junction

Js 支持

我们很高兴地宣布,这个Laravel-Junction包现在有一个配套的JavaScript/TS库!这个新增功能将我们的Laravel包的功能扩展到前端,为您的Web应用程序提供无缝集成。

开发

为了轻松在本地工作并使用该包在其他本地项目中,请执行以下操作

  1. 在您想包含Laravel-Junction的项目中,向composer.json文件添加一个存储库
"repositories": {
    "laravel-junction": {
        "type": "path",
        "url": "./laravel-junction",
        "options": {
            "symlink": true
        }
    }
}
  1. 如果您的其他项目在docker中运行,请添加一个指向Laravel-Junction所在文件夹的卷
services:
  api:
    image: ...
    volumes:
      - ../laravel-junction:/var/www/laravel-junction
  1. 安装本地包。您之前在存储库中设置的symlink选项确保您只需这样做一次,而不是每次代码更改时都这样做。
composer require weapnl/laravel-junction dev-main

快速入门

// app/Http/Controllers/API/UserController.php
namespace App\Http\Controllers\API;

use Weap\Junction\Http\Controllers\Controller;

class UserController extends Controller
{
    /**
     * The class name of the model for which the controller should implement CRUD actions.
     *
     * @var string
     */
    public $model = User::class;

    /**
     * Define the relations which can be loaded in a request using "array" notation.
     *
     * @return array
     */
    public function relations(): array
    {
        return [
            'orders',
        ];
    }
// routes/api.php
Junction::apiResource('users', 'UserController');

现在您已经准备好了。您现在可以向/api/users端点发出请求。尝试一个POST请求来创建新用户,或一个GET请求来检索所有用户。

用法

设置控制器

为了让控制器可以通过API访问,您需要扩展Weap\Junction\Http\Controllers\Controller类。这个类扩展了默认的Laravel控制器,并添加了一些额外功能。定义控制器非常简单,请查看快速入门部分的基本示例。我们现在将介绍一些额外功能。

// app/Http/Controllers/API/UserController.php
namespace App\Http\Controllers\API;

use Weap\Junction\Http\Controllers\Controller; // Make sure to import the Controller class from the Weap/Junction package.

class UserController extends Controller
{
    /**
     * The class name of the model for which the controller should implement CRUD actions.
     *
     * @var string
     */
    public $model = User::class;
    
    /**
     * The class name of Resource to be used for the show and index methods.
     *
     * @var string $resource
     */
    public $resource = UserResource::class;

    /**
     * Define the relations which can be loaded in a request using "array" notation.
     *
     * @return array
     */
    public function relations(): array
    {
        return [
            'orders',
            // Define all your relations here with should be accessible through the API.
        ];
    }

示例用法

/api/users?orders[0][column]=id&orders[0][direction]=asc&&search_value=john&search_columns[]=name&search_columns[]=email

示例响应

即使您没有使用分页,响应也始终包含属性itemstotalpage

{
  "items": [
    {
      "id": 2,
      "name": "John Doe",
      "email": "john.doe@app.com",
      "orders": [],
      "comments": [
        {
          "id": 1,
          "body": "Hello world!"
        }
      ]
    }
  ],
  "total": 1, // Total amount of items
  "page": 1 // The current page
}

筛选器

筛选器应用于查询。筛选器使用数组键定义。可用的筛选器

修改器

修改器在查询运行后应用。可用的修改器

分页

分页在数据库级别应用(在应用所有筛选器之后)。以下参数可用于设置分页

简单分页

简单分页几乎与上述分页相同。但简单分页不返回项目总数或页码。这对于大型数据库表很有用,因为正常分页太慢。

关系

要限制可以使用with筛选器加载的关系,您可以在控制器上覆盖relations方法。此方法应返回一个包含关系(支持点表示法)的数组。要向关系查询添加筛选器,您可以使用关系名称作为键,闭包作为值。

注意:当使用点表示法时,如果为较高层次的关系提供了一个闭包,则该闭包将应用于查询。例如,如果关系实现如下,加载关系user.activities将应用isAdmin作用域到用户查询。

public function relations()
{
    return [
        'user' => fn($query) => $query->isAdmin(),
        'user.activities',
    ];
}

搜索

此包支持针对给定模型和关系的搜索功能。在您的控制器中,添加以下定义的可搜索属性。当您想要搜索一个模型时,请在请求中添加 "search_value"。可选地,您可以添加 "search_columns" 来覆盖控制器中的列。

public $searchable = [
    'id',
    'name',
    'orders.order_number',
];

资源

要使用资源,请在控制器中设置 resource 变量。您的资源必须扩展 \Weap\Junction\Http\Controllers\Resources

这允许您指定将返回哪些属性、访问器和关系。为此,覆盖相应的方法

  • availableAttributes。返回一个字符串数组,指定将返回哪些属性。主键始终包含在内。
  • availableAccessors。返回一个字符串数组,指定将返回哪些访问器。
  • availableRelations。返回一个键/值对数组,其中键是关系的名称,值是另一个资源。

在这些方法中的任何一种中返回 null 以允许返回 ALL 属性/访问器/关系。

示例

class UserResource extends BaseResource
{
    /**
     * @return array|null
     */
    protected function availableAttributes(): ?array
    {
        return [
            'first_name'
        ];
    }

    /**
     * @return array|null
     */
    protected function availableAccessors(): ?array
    {
        return [
            'fullName'
        ];
    }

    /**
     * @return array|null
     */
    protected function availableRelations(): ?array
    {
        return [
            'orders' => OrderResource::class,
        ];
    }
}

操作

此包还支持动作路由。

在您的控制器中添加动作方法

/**
 * @param null|Model $model
 */
protected function actionSomeName($model = null)
{
    //
}
  • 如果您正在使用策略,则您的策略应实现 action 策略,该策略接受模型作为参数。
  • 现在,您可以通过以下路由作为 PUT 请求进行调用:/api/users。在主体中,添加以下内容(id是可选的)
{
    "action": "someName",
    "id": 1
}
  • 您可以根据需要添加尽可能多的动作。只需确保将方法前缀为 action

验证

FormRequest验证

要验证传入的请求,您可以创建一个 FormRequest 并扩展 Weap\Junction\Http\Controllers\Requests\DefaultFormRequest 类。此类扩展了默认的Laravel FormRequest类,并添加了一些额外功能。

标准验证

要验证请求,为您的模型创建一个请求文件并将其添加到控制器中。

/**
 * The class name of FormRequest to be used for the store and update methods.
 *
 * @var string
 */
public $formRequest = ModelRequest::class;
  • ModelRequestrules() 方法中添加规则。
/**
 * Get the validation rules that apply to the request.
 *
 * @return array
 */
public function rules()
{
    return [
        'first_name' => 'required',
    ];
}

/**
 * Define validation rule messages for store and update requests.
 *
 * @return array
 */
public function messages()
{
    return [
        'first_name.required' => 'The first name is required.',
    ];
}

保存可填充属性

默认情况下,调用store/update路由时只保存经过验证的属性。要保存可填充属性,请在控制器中设置以下内容

/**
 * Set to true to save fillable instead of validated attributes in store/update methods.
 *
 * @var bool
 */
protected $saveFillable = true;

使用 Spatie Medialibrary 的临时媒体文件

步骤 1:通过API上传文件

要通过API上传文件,请使用 /media/upload 端点。在请求体中包含一个位于 files 键下的文件数组。这些文件将临时存储在媒体库中,并与 MediaTemporaryUpload 模型关联。

示例上传请求

{
    "files": [<uploaded file here>, ...]
}

步骤 2:将文件附加到模型

示例 A:更新现有模型

要将文件附加到现有模型,请将媒体ID包含在 PUT 请求中。例如,如果您想将身份证件附加到员工身上,您的 PUT 请求可能如下所示,假设身份证件存储在 Employee 模型上的 IdentityFiles 集合

{
    "first_name": "John",
    "last_name": "Doe",
    "_media": {
        "IdentityFiles": [1]
    }
}

API将在请求体中搜索 _media 键并将指定的媒体ID与正确的集合关联起来。在此示例中,媒体ID 1将附加到ID为3的 EmployeeIdentityFiles 集合中。

示例 B:创建新模型

您还可以在创建新模型时通过 POST 请求附加文件。例如,如果您正在创建新的 Employee 并希望附加一张个人照片,您的 POST 请求可能如下所示

{
    "first_name": "Jane",
    "last_name": "Smith",
    "_media": {
        "ProfilePicture": [2]
    }
}

这将把媒体ID 2附加到新创建的 EmployeeProfilePicture 集合中。

在嵌套结构中使用 _media

在请求数据体中,_media键也可以嵌套使用,例如,可以嵌套在contact键内部。在这种情况下,API会将媒体文件附加到Employeecontact关系上,无论您是在创建新模型还是更新现有模型。

嵌套_media键的示例请求(用于创建)

{
    "first_name": "Jane",
    "last_name": "Smith",
    "contact": {
        "phone": "123-456-7890",
        "_media": {
            "ProfilePicture": [3]
        }
    }
}

在这个示例中,当创建一个新的Employee时,媒体ID 3将被附加到新Employeecontact关系中的ProfilePicture集合中。