Laravel6 全套入门实战Eloquent ORM 使用
课程内容
简介
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_at
和 updated_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_AT
和 UPDATED_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 模型都默认不可进行批量赋值 ,通过 fillable
或 guarded
来定义哪些可定义和不能定义,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 模型触发几个事件,允许你挂接到模型生命周期的如下节点: retrieved
、creating
、created
、updating
、updated
、saving
、saved
、deleting
、deleted
、restoring
和 restored
。事件允许你每当特定模型保存或更新数据库时执行代码。每个事件通过其构造器接受模型实例。
retrieved
事件在现有模型从数据库中查找数据时触发。当新模型每一次保存时,creating
和 created
事件被触发。如果数据库中已经存在模型并且调用了 save
方法,updating
/ updated
事件被触发。这些情况下,saving
/ saved
事件也被触发。
注意:通过 Eloquent 进行批量更新时,被更新模型的
saved
和updated
事件不会被触发。这是因为批量更新时,并没有真的获取模型。
首先,在 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 事件,就可以使用 事件监听 处理这些事件了。