上周我在团队内做了 Laravel 入门分享,希望能够帮助对这款框架不熟悉的同学快速上手,最好听完就能撸个接口。作为前端小哥的我自知对后端了解有限,于是我事先写了个 demo,围绕一个假定的需求 —— 学生信息的增删改查来讲这堂课。

这篇文章假设读者已经掌握 Laravel 的安装,若不了解请先移步 文档

数据库

迁移

首先我们要建一个班级表和一个学生表。Laravel 提供了迁移(migration)功能用于创建和更新数据表。

简单地说,我们把表结构用编程的方式写在文件中,然后执行这些文件,达到建表和更新表结构的目的。每个迁移文件都包含一个 up 方法和一个 down 方法,分别用于执行和回滚迁移。

在 CLI 执行以下命令创建两张表的迁移文件:

php artisan make:migration create_classes_table
php artisan make:migration create_students_table

此时可在 database/migrations 目录下找到新增的 2 个迁移文件。

我们先来看看 classes 表的迁移文件,Laravel 已经帮我们写了一些代码。

Schema::create('classes', function (Blueprint $table) {
    $table->increments('id');  // 创建一个自增的 id 字段
    $table->timestamps();      // 创建 created_at 和 updated_at 字段
});

我增加了一个 name 字段,用来保存班级名称。实际上,这句代码在数据库中创建的是一个 varchar 类型,最大长度 16 个字符的字段。

$table->string('name', 16);

接下来编辑 students 表的迁移文件:

Schema::create('students', function (Blueprint $table) {
    $table->increments('id');
    $table->string('number', 16);     // 学生编号
    $table->string('name', 16);       // 学生姓名
    $table->tinyInteger('class_id');  // 班级 ID
    $table->timestamps();
    $table->softDeletes();            // 创建 deleted_at 字段
});

然后在 CLI 中执行 php artisan migrate 运行迁移,数据库中便创建了 classesstudentsmigrations 等表。

migrations 表用于记录执行过哪些迁移。

created_atupdated_at 字段分别用于存储创建时间和更新时间。当使用 Eloquent ORM 方式修改数据时,它们将自动更新。

deleted_at 字段用于软删除数据,即记录不会真的从数据库中删除,而是存储一个删除时间,这些数据便不会再被查询出来。

填充

有时候我们希望给数据表批量写入一些数据。例如,在建完 classes 表后将已知的所有班级信息插入到表中。Laravel 提供了填充(seed)功能用于填充测试数据。

在 CLI 执行以下命令创建一个填充器。

php artisan make:seeder ClassesTableSeeder

编辑 database/seeds 目录下新增的 ClassesTableSeeder.php ,在 run 方法中插入代码:

DB::table('classes')->insert(['name' => '三年一班']);
DB::table('classes')->insert(['name' => '三年二班']);
DB::table('classes')->insert(['name' => '三年三班']);

执行以下命令运行填充器:

php artisan db:seed --class=ClassesTableSeeder

然后便可以在 classes 表中看见刚刚填充进去的 3 个班级。

路由

API 路由应该在 route/api.php 中声明,Route 类提供了 get/post/patch/delete 等路由方法用于定义不同类型的路由。

我们先定义一个简单的路由:

Route::get('hello', function (Request $request) {
    $name = $request->input('name');         // 获取请求参数
    return "Hello Laravel, I am {$name} !";  // 响应字符串内容
});

然后我们访问 http://{你的域名}/api/hello?name=YIMING,浏览器将显示:

Hello Laravel, I am YIMING !

通过这个 Hello World 路由可以知道,路由方法的第一个参数是 URI ,第二个参数是一个 callback 。

URI 中可以使用 {} 声明路由参数,并在回调函数中使用:

Route::get('hello/{name}', function ($name) {
    return "Hello Laravel, I am {$name} !";
});

路由也可以指向某个控制器动作(方法):

Route::get('students', 'StudentController@index');
Route::post('students', 'StudentController@store');
Route::get('students/{student}', 'StudentController@show');
Route::patch('students/{student}', 'StudentController@update');
Route::delete('students/{student}', 'StudentController@destory');

如果控制器是一个符合要求的 RESTful 资源控制器(见下文),上面这些路由等价于。

Route::resource('students', 'StudentController');

模型

Laravel 提供了 Eloquent ORM(对象关系映射),一个模型对应一张数据表,通过模型类操作数据表。模型文件默认放在 app 目录下。

举个例子,假设存在 User 模型,那么它将默认对应数据库中的 users 表,我们可以这样查询数据:

User::where('id', 1)->get(); // 查询 id 等于1的用户

执行以下命令分别为班级表、学生表创建模型:

php artisan make:model StudentClass
php artisan make:model Student

Student 模型默认对应 students 表。

对于 StudentClass 模型,我们可以显式地声明它的关联表为 classes

class StudentClass extends Model
{
    protected $table = 'classes';
}

然后编辑 Student 模型:

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Student extends Model
{
    // 启用软删除
    use SoftDeletes;
    // 可被批量赋值的字段
    protected $fillable = [
        'number',
        'name',
        'class_id'
    ];
    // 与班级表的关联关系
    public function studentClass ()
    {
        return $this->hasOne('App\StudentClass', 'id', 'class_id');
    }
}

控制器

基础

在路由小节中,我们注册了一个指向 StudentController 控制器的资源路由。

Route::resource('students', 'StudentController');

执行以下命令创建 StudentController 控制器:

php artisan make:controller StudentController 

由于 StudentController 是一个资源控制器,下列请求将自动指向相应控制器方法。

请求方式 URI 控制器方法 操作
GET /api/students index 查询全部
GET /api/students/{student} show 查询单条
POST /api/students store 创建
PATCH /api/students/{student} update 修改
DELETE /api/students/{student} destroy 删除

首先,在控制器中导入 Request、Validator 和 Student 模型:

use Illuminate\Http\Request;
use Validator;
use App\Student;

请求类(Request)用于获取参数,验证类(Validator)用于验证参数的合法性,Student 模型用于 students 表的增删改查操作。

查询

index 方法使用模型查询数据表,然后返回学生列表:

public function index ()
{
    // 查询全部记录
    return Student::all();
    // 查询三年一班的学生
    return Student::where('class_id', '1')->get();
    // 查询前两个班的学生
    return Student::where('class_id', '<=', '2')->get();
    // 包含软删除的记录
    return Student::withTrashed()->get();
    // 分页 每页15条记录
    return Student::paginate(15);
    // 同时查询关联数据
    return Student::with('studentClass')->get();
}

启用分页时,返回的结果中会包含页码、总页数等数据。

在请求时传递 page 可以查询指定页码的数据,否则默认返回第一页。

/api/students?page=2

由于在 Student 模型中声明了和 StudentClass 模型(即班级表)的关联关系,我们可以使用 with 同时查出学生的班级信息。

[{
    number: '2018090201'
    name: '张三'...
    studentClass: {
        name: '三年一班',
        ...
    }
}]

show 方法接收一个路由参数,返回指定 id 的学生:

public function show ($id)
{
    return Student::find($id);
}

新增

store 方法接收用户输入,验证参数的合法性,然后创建一名学生。这里不再赘述验证(Validation)功能的用法,感兴趣的同学可以移步官方文档了解。

public function store (Request $request)
{
    // 验证器
    $validator = Validator::make($request->all(), [
        // 必填,在 students 表中唯一,不多于10个字符。
        'number' => 'required|unique:students|max:10',
        // 必填,不多于8个字符。
        'name' => 'required|max:8',
        // 必填,只能是1、2或3。
        'class_id' => 'required|in:1,2,3'
    ]);
2// 当验证失败时响应 422 错误
    if ($validator->fails()) {
        return response($validator->errors(), 422);
    }
    return Student::create($request->all());
}

修改

update 方法接收用户输入和路由参数(学生 id),然后更新相应学生的信息。

public function update (Request $request, $id)
{
    Student::where('id', $id)->update($request->all());
}

删除

destroy 方法接收一个路由参数(学生 id),然后删除相应的学生。由于模型中启用了软删除,不会真的从数据表中删除记录,而是更新其 deleted_at 字段。

public function destory ($id)
{
    Student::destroy($id);
}

最后

你可以在 Postman 中调试一下这几个接口了,happy hacking !

相关链接:

相关环境:macOS 10.13 / Laravel Homestead / Laravel 5.6