课程内容

简介

Laravel 的 Eloquent ORM 提供了一个漂亮、简洁的 ActiveRecord 实现来和数据库交互。每个数据库表都有一个对应的「模型」用来与该表交互。你可以通过模型查询数据表中的数据,以及在数据表中插入新记录。

在开始之前,请确保在 config/database.php 中配置数据库连接。

模型定义

首先,创建一个 Eloquent 模型。 模型通常在 app 目录中,但你可以根据 composer.json 文件将他们放置在可以被自动加载的任意位置。所有的 Eloquent 模型都继承至 Illuminate\Database\Eloquent\Model 类。

创建模型最简单的方法就是使用 make:model Artisan 命令

php artisan make:model Flight

如果要在生成模型的时候生成 数据库迁移 ,可以使用 --migration-m 选项:

php artisan make:model Flight --migration

php artisan make:model Flight -m

数据表名称

请注意,我们并没有告诉 Eloquent 我们的 Flight 模型使用哪个数据表。 除非明确地指定了其它名称,否则将使用类的复数形式「蛇形命名」来作为表名。因此,在这种情况下,Eloquent 将假设 Flight 模型存储的是 flights 数据表中的数据。你可以通过在模型上定义 table 属性来指定自定义数据表:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    /**
     * 与模型关联的表名
     *
     * @var string
     */
    protected $table = 'my_flights';
}

主键

Eloquent 也会假设每个数据表都有一个名为 id 的主键列。你可以定义一个受保护的 $primaryKey 属性来重写约定。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    /**
     * 重定义主键
     *
     * @var string
     */
    protected $primaryKey = 'flight_id';
}

此外,Eloquent 假设主键是一个自增的整数值,这意味着默认情况下主键会自动转换为 int 类型。如果您希望使用非递增或非数字的主键则需要设置公共的 $incrementing 属性设置为 false

<?php

class Flight extends Model
{
    /**
     * 指示模型主键是否递增
     *
     * @var bool
     */
    public $incrementing = false;
}

如果你的主键不是一个整数,你需要将模型上受保护的 $keyType 属性设置为 string

<?php

class Flight extends Model
{
    /**
     * 自动递增ID的“类型”。
     *
     * @var string
     */
    protected $keyType = 'string';
}

时间戳

默认情况下,Eloquent 预期你的数据表中存在 created_atupdated_at 。如果你不想让 Eloquent 自动管理这两个列, 请将模型中的 $timestamps 属性设置为 false

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    /**
     * 指示是否自动维护时间戳
     *
     * @var bool
     */
    public $timestamps = false;
}

如果需要自定义时间戳的格式,在你的模型中设置 $dateFormat 属性。这个属性决定日期属性在数据库的存储方式,以及模型序列化为数组或者 JSON 的格式:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    /**
     * 模型日期列的存储格式。
     *
     * @var string
     */
    protected $dateFormat = 'U';
}

如果你需要自定义存储时间戳的字段名,可以在模型中设置 CREATED_ATUPDATED_AT 常量的值来实现:

<?php

class Flight extends Model
{
    const CREATED_AT = 'creation_date';
    const UPDATED_AT = 'last_update';
}

数据库连接

默认情况下,Eloquent 模型将使用你的应用程序配置的默认数据库连接。如果你想为模型指定一个不同的连接,设置 $connection 属性:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    /**
     * 模型的连接名称
     *
     * @var string
     */
    protected $connection = 'connection-name';
}

查询

$flights = App\Flight::all();

$flights = App\Flight::where('active', 1)
               ->orderBy('name', 'desc')
               ->take(10)
               ->get();

未找到』异常

有时你希望在未找到模型时抛出异常。这在控制器和路由中非常有用。 findOrFail 和 firstOrFail 方法会检索查询的第一个结果,如果未找到,将抛出 Illuminate\Database\Eloquent\ModelNotFoundException 异常:

$model = App\Flight::findOrFail(1);

$model = App\Flight::where('legs', '>', 100)->firstOrFail();

插入

 $flight = new Flight;

        $flight->name = $request->name;

        $flight->save();

更新

$flight = App\Flight::find(1);

$flight->name = 'New Flight Name';

$flight->save();

批量更新

App\Flight::where('active', 1)
          ->where('destination', 'San Diego')
          ->update(['delayed' => 1]);

批量赋值

所有的 Eloquent 模型都默认不可进行批量赋值 ,通过fillableguarded来定义哪些可定义和不能定义,2个不能同时使用,只能用一个。定义后才可以使用create设置

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    /**
     * 可以被批量赋值的属性。
     *
     * @var array
     */
    protected $fillable = ['name'];
}
$flight = App\Flight::create(['name' => 'Flight 10']);

如果你想让所有属性都可以批量赋值, 你可以将 $guarded 定义成一个空数组:

protected $guarded = [];

删除模型

$flight = App\Flight::find(1);

$flight->delete();

App\Flight::destroy(1);

App\Flight::destroy(1, 2, 3);

App\Flight::destroy([1, 2, 3]);

App\Flight::destroy(collect([1, 2, 3]));

软删除

你需要在模型上使用Illuminate\Database\Eloquent\SoftDeletes

<?php

namespace App;

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

class Flight extends Model
{
    use SoftDeletes;
}

查询软删除模型

 $flights = App\Flight::withTrashed()
                ->where('account_id', 1)
                ->get();

恢复软删除模型

$flight->restore();

永久删除

// 强制删除单个模型实例...
$flight->forceDelete();

// 强制删除所有相关模型...
$flight->history()->forceDelete();

全局作用域

定义一个实现 Illuminate\Database\Eloquent\Scope 接口的,并实现 apply 这个方法。根据你的需求,在 apply 方法中加入查询的 where 条件

<?php

namespace App\Scopes;

use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

class AgeScope implements Scope
{
    /**
     * 把约束加到 Eloquent 查询构造中。
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */
    public function apply(Builder $builder, Model $model)
    {
        $builder->where('age', '>', 200);
    }
}

应用全局作用域

需要重写模型的 boot 方法并使用 addGlobalScope 方法:

<?php

namespace App;

use App\Scopes\AgeScope;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * 模型的「启动」方法
     *
     * @return void
     */
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope(new AgeScope);
    }
}

匿名全局作用域

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

class User extends Model
{
    /**
     * 模型的「启动」方法
     *
     * @return void
     */
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope('age', function (Builder $builder) {
            $builder->where('age', '>', 200);
        });
    }
}

取消全局作用域

User::withoutGlobalScope(AgeScope::class)->get();
User::withoutGlobalScope('age')->get();

// 取消所有的全局作用域...
User::withoutGlobalScopes()->get();

// 取消部分全局作用域...
User::withoutGlobalScopes([
    FirstScope::class, SecondScope::class
])->get();

本地作用域

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * 只查询受欢迎的用户的作用域
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopePopular($query)
    {
        return $query->where('votes', '>', 100);
    }

    /**
     * 只查询 active 用户的作用域
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeActive($query)
    {
        return $query->where('active', 1);
    }
}

调用

$users = App\User::popular()->active()->orderBy('created_at')->get();

事件

Eloquent 模型触发几个事件,允许你挂接到模型生命周期的如下节点: retrievedcreatingcreatedupdatingupdatedsavingsaveddeletingdeletedrestoringrestored。事件允许你每当特定模型保存或更新数据库时执行代码。每个事件通过其构造器接受模型实例。

retrieved 事件在现有模型从数据库中查找数据时触发。当新模型每一次保存时,creatingcreated 事件被触发。如果数据库中已经存在模型并且调用了 save 方法,updating / updated 事件被触发。这些情况下,saving / saved 事件也被触发。

注意:通过 Eloquent 进行批量更新时,被更新模型的 savedupdated 事件不会被触发。这是因为批量更新时,并没有真的获取模型。

首先,在 Eloquent 模型上定义一个 $dispatchesEvents 属性,将 Eloquent 模型生命周期的几个节点映射到你自己的 event 类

<?php

namespace App;

use App\Events\UserSaved;
use App\Events\UserDeleted;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    /**
     * 模型的事件映射
     *
     * @var array
     */
    protected $dispatchesEvents = [
        'saved' => UserSaved::class,
        'deleted' => UserDeleted::class,
    ];
}

定义并且映射了 Eloquent 事件,就可以使用 事件监听 处理这些事件了。

评论区 (0)

没有记录
支持 markdown,图片截图粘贴拖拽都可以自动上传。