API知识库 > 使用研讨 > 具有嵌套关系的可重用API资源——Laravel5.5
具有嵌套关系的可重用API资源——Laravel5.5

具有嵌套关系的可重用API资源——Laravel5.5

本文内容主要围绕在 Laravel 5.5 中使用 API 开发的重要步骤,着重介绍如何利用 Laravel 的 API 资源(Resource)和控制器(Controller)进行多因素身份验证(MFA)。尤其强调了利用 Resource::collection 方法简化数据提供过程,以及对比 Fractal 和 Laravel 的资源处理方式。

注:本文受到Laravel创始人Taylor Otwell介绍使用 Laravel5.5 开发API时如何替换 

Fractal 的启发。

1.  安装一个干净的 Laravel 5.5 项目

· 使用 Composer 命令 composer create-project laravel/laravel responses dev-develop 来创建一个 Laravel 5.5 项目。这个命令会从 Laravel 官方的存储库中下载最新版本的 Laravel 5.5 代码并安装到名为 “responses” 的文件夹中。

· cd responses: 进入到新创建的 “responses” 文件夹中。

· touch database/database.sqlite: 创建一个 SQLite 数据库文件,用于存储数据。

php artisan make:model Post -mf: 创建一个名为 “Post” 的 Eloquent 模型,并生成相应的迁移文件和工厂。

· php artisan make:resource UsersWithPostsResource: 创建一个名为 “UsersWithPostsResource” 的资源类,用于对用户及其posts进行处理。

· php artisan make:resource PostsResource: 创建一个名为 “PostsResource” 的资源类,用于对posts进行处理。

· php artisan make:controller UsersController –resource: 创建一个名为 “UsersController” 的控制器,添加了 CRUD(创建、读取、更新、删除)操作的资源路由。

· 修改 .env 文件,使用 SQLite 数据库,并删除其他数据库相关的变量。

· 添加或修改 DB_CONNECTION=sqlite 来指定 Laravel 使用 SQLite 作为数据库连接。

这些步骤旨在建立一个基本的 Laravel 5.5 项目,并做了一些初始化设置,包括创建模型、资源类和控制器,并配置使用 SQLite 作为数据库。

2.  准备数据库

·posts迁移 database/migrations/______create_posts_table.php

Schema::create('posts', function (Blueprint $table) {
    $table->increments('id');
    $table->string('title');
    $table->string('body');
    $table->unsignedInteger('user_id');
    $table->timestamps();
});

这涉及创建posts模型的数据库表结构。在 database/migrations 目录下的create_posts_table.php 的文件,定义了posts表的字段和结构。这个文件包含了使用 Laravel 的迁移(Migration)功能创建数据库表的代码。

· posts工厂database/factories/PostFactory.php

<?php
use Faker\Generator as Faker;
$factory->define(App\Post::class, 
function (Faker $faker) {
    return [
        'title' => $faker->sentence,
        'body' => $faker->paragraph,
        'user_id' => function () {
            return factory(\App\User::class);
        }
    ];
});

这一步骤是为了创建一个posts的工厂,用于生成测试数据或者用于种子数据填充。在 database/factories 目录下的 PostFactory.php 文件中,你会定义创建posts模型时所用的数据格式和规则。

· 用户拥有posts的关系 app/User.php

public function posts(){return $this->hasMany(Post::class);}

这是在用户模型(User)中定义与posts模型的关系。也就是在 app 目录下的 User.php 文件中,你会定义用户和posts之间的关联关系,比如一对多关系(一个用户有多个posts)或其他关系。

· 避免批量赋值 app/Post.php

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;

class Post extends Model{protected $guarded = [];}

在 app 目录下的 Post.php 文件中,通常会有一个模型类,即posts模型(Post)。避免批量赋值是指使用 Laravel 的属性来指定哪些字段可以被批量赋值,以防止不受控制的数据注入。

· 播种数据库

<?php 
artisan migrate:freshphp artisan 
tinkerfactory(App\Post::class)->times(2)->create();
factory(App\Post::class)->times(2)->create(['user_id' => 1]);

数据库种子用于向数据库中填充测试数据或初始数据。这是在开发或测试阶段常用的操作,可以使用 Laravel 的 Seeder 来填充数据库表,确保数据库中有一些初始数据可用于开发和测试。

3.  设置路由

Route::apiResource('/users', 'UsersController');

4.  重命名资源(修复遗留问题)

之前创建了一个名为 UsersWithPostsResource 的资源。让我们将其重命名为 UsersResource,并了解如何在以下步骤中重用它。

5.  在控制器内使用API资源

<?php

/**
 * Display a listing of the resource.
 *
 * @param User $user
 * @return \Illuminate\Http\Response
 */
public function index(User $user)
{
    return UsersResource::collection($user->with('posts')->paginate());
    // If you don't want to include the relationship in your response, don't use with()
    // return UsersResource::collection($user->paginate());
}

静态 collection 方法将采用要转换的记录集合,并确保为每个记录实例化一个新的UsersResource

6.  UsersResource类

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\Resource;

class UsersResource extends Resource
{
    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request
     * @return array
     */
    public function toArray($request)
    {
        return [
            'name' => $this->name,
            'email' => $this->email,
            'posts' => PostsResource::collection($this->whenLoaded('posts'))
        ];
    }
}

这里的两个关键部分:属性访问器可选的嵌套转换

Resource 中,可以通过 $this 直接访问模型的属性。这个神奇的功能是通过 DelegatesToResource trait 在基础资源类中实现的。简单来说,这意味着资源类中可以直接使用 $this->attributeName 的方式访问模型中的属性,而不必每次都通过模型实例去获取属性。

能够在资源类中进行关系的转换,但是有条件:如果数据是可用的(已经预加载),就可以进行转换;如果数据尚未加载,可以选择忽略这个转换。这样做有利于避免 N+1 查询问题(在获取关联数据时出现的效率问题),同时可以使用单个资源类处理不同的情况。如果关联数据不可用,资源类会忽略它;反之,如果可用,资源类会将其包含在返回的数据中。

7.  Posts Resource

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\Resource;

class PostsResource extends Resource
{
    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request
     * @return array
     */
    public function toArray($request)
    {
        return [
            'title' => $this->title,
            'body' => $this->body
        ];
    }
}

结论

1.简化和逐步进行
本文着重于学习如何使用 Resource::collection 而不是手动实例化类,并将关系数据的提供(或不提供)责任委托给控制器。通过在控制器中简单地移除 with(‘posts’),API 将不再在响应中包含每个用户的posts数据。

2.对比 Fractal 和 Laravel 的资源
本文提到 Fractal 在转换层(Transformer)提供了默认和可用的包含(includes)功能,但是 Laravel 的原生 API 资源更倾向于让控制器处理这个逻辑。毕竟,控制器的工作是理解请求。这暗示着对于数据包含的处理,Laravel 更多地依赖于控制器层面的逻辑,而不是在资源转换层实现。

总体而言,本文聚焦于利用 Laravel 中的 Resource::collection,并强调控制器对于处理数据关系包含的重要性。

参考链接:

First impressions on Laravel API Resources | HackerNoon

具有嵌套关系的可重用 API 资源 — Laravel 5.5 |由 Marco Aurélio Deleu |HackerNoon.com |中等 (medium.com)

#你可能也喜欢这些API文章!