前言
一、大纲
写后端API,与数据库打交道无疑是很重要的角色。
Ref: [PHP] 07 - Json, XML and MySQL
二、细节
三、初识 Eloquent ORM
Eloquent ORM是Laravel框架使用的ORM。Laravel 的 Eloquent ORM 提供了更优雅的ActiveRecord 实现来和数据库的互动。每个数据库表对应一个模型文件。
Goto: Eloquent: 入门【2.完整复习版本】
From: Eloquent ORM笔记【1.基础篇】
新增
# 新建了一条 id, name
$user = new User;
$user->name = 'John';
$user->save();
$insertedId = $user->id;//从对象取得 id 属性值 使用模型的 Create 方法
class User extends Model {
protected $guarded = ['id', 'account_id']; //黑名单,不会被更新
} // 建立一个用户
$user = User::create(['name' => 'John']); // 以属性找用户 - 若没有则新增并取得新的实例...
$user = User::firstOrCreate(['name' => 'John']); // 以属性找用户 - 若没有则建立新的实例...
$user = User::firstOrNew(['name' => 'John']); 辨析
firstOrCreate:判断之后直接入库
firstOrNew :判断之后还要做其他业务流程,之后再入库
删除
$this->where($where)->delete(); 或者
$user = User::find(1);
$user->delete(); 更新
return $this->where($where)->update($data); 或者
$user = User::find(1);
$user->update($data); 查找
//取出所有记录 - 可以遍历
$this->all()->toArray(); //取出一条数据
$one = $this->find('2');
return array(
$one->id,
$one->title,
$one->content,
); //查找id=2的第一条数据
$this->where('id', 2)->first()->toArray(); //查找id>0的所有数据
$this->where('id', '>', '0')->get()->toArray();
- For
find(n)
, you retrieve a row based on the primary key which is 'n'. - For
first()
, you retrieve the first row among all rows that fit the where clauses. - For
get()
, you retrieve all the rows that fit the where clauses. (Please note that loops are required to access all the rows or you will get some errors).
//降序排列
$this->where('id', '>', '0')->orderBy('id', 'desc')->get()->toArray(); //降序排列,计数
$this->where('id', '>', '0')->orderBy('id', 'desc')->count(); //从offset起始算起的limit条数据
$this->where('id', '>', '0')->orderBy($order[0], $order[1])->skip($offset)->take($limit);
//等同于
$this->where('id', '>', '0')->orderBy($order[0], $order[1])->offset($offset)->limit($limit); 条件类
//条件类
where('id', '>', '0')
where('id', '>=', '0')
where('id', '<', '0')
where('id', '<=', '0')
where('id', 'like', 'name%') whereIn($key, $array)
whereNotIn($key, $array)
whereBetween($key, $array)
whereNotBetween($key, $array) orWhereIn($key, $array)
orWhereNotIn($key, $array)
orWhereBetween($key, $array)
orWhereNotBetween($key, $array) 结果方法
//结果方法:Illuminate\Database\Query\Builder
first()取第一个
get()取所有
all()取所有(无条件) 数学统计
//聚合方法
count()
avg()
sum()
max()
min()
Pure SQL
RDBMS 指关系型数据库管理系统,全称 Relational Database Management System。
(1). 登录:mysql -u root -p
(2). phpMyAdmin创建数据库,并导入.sql文件。
(3). 支持中文:set names utf8;
Eloquent: 入门
{tip} 由于 Eloquent 模型是查询构造器,因此你应当去阅读所有 查询构造器 中可用的方法。
一、模型
- 生成模型、迁移文件
php artisan make:model User --migration
php artisan make:model User -m
<?php namespace App; use Illuminate\Database\Eloquent\Model; # 所有的 Eloquent 模型都继承自这个 class Flight extends Model
{
// 用它从flights
数据表中取回与保存信息
}
- 默认常用四属性
[1] 表名
除非数据表明确地指定了其它名称,否则将使用类的「蛇形名称」、复数形式名称来作为数据表的名称。自定义对应表名:
protected $table = 'my_flights';
[2] 主键
设每个数据表都有一个叫做 id
的主键字段。你也可以定义一个 $primaryKey
属性来重写这个约定。
默认是递增;否则,必须在你的模型 public $incrementing=
false
。
[3] 时间戳
默认情况下,Eloquent 会认为在你的数据库表有 created_at
和 updated_at
字段。
如果你不希望让 Eloquent 来自动维护这两个字段,可在模型内将 $timestamps=
false。
决定了日期应如何在数据库中存储,以及当模型被序列化成数组或 JSON 格式 protected $dateFormat = 'U';
[4] 连接数据库
默认情况下,所有的 Eloquent 模型会使用应用程序中默认的数据库连接设置。
如果你想为模型指定不同的连接,可以使用 protected $connection = 'connection-name';
[5] 通过模型获取结果
$flights = App\Flight::where('active', 1) ->orderBy('name', 'desc') ->take(10) ->get();
- 模型创建与删除
详见:"三、初识 Eloquent ORM"
补充:软删除
模型上设置一个 deleted_at
属性并将其添加到数据库。如果模型有一个非空值 deleted_at
,代表模型已经被软删除了。
[1] 设置字段
当模型被软删除时,它们并不会真的从数据库中被移除。而是会在模型上设置一个 deleted_at
属性并将其添加到数据库。
如果模型有一个非空值 deleted_at
,代表模型已经被软删除了。
<?php namespace App; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; class Flight extends Model
{
use SoftDeletes; /**
* 需要被转换成日期的属性。
* 添加deleted_at
字段到你的$dates
属性。
*
* @var array
*/
protected $dates = ['deleted_at'];
}
[2] 添加 deleted_at
字段到数据表
Schema::table('flights', function ($table) {
$table->softDeletes();
});
当查询有启用软删除的模型时,被软删除的模型将会自动从所有查询结果中排除。
[3] 查询 deleted_at 字段
确认指定的模型实例是否已经被软删除,可以使用 trashed
方法:
if ($flight->trashed()) {
//
}
[4] 查询捎带上 '软删除‘ 集合
$flights = App\Flight::withTrashed()
->where('account_id', 1)
->get();
[5] 只查询 ‘软删除’ 集合
$flights = App\Flight::onlyTrashed()
->where('airline_id', 1)
->get();
[6] 恢复 '软删除'
$flight->restore(); App\Flight::withTrashed() ->where('airline_id', 1) ->restore();
[7] 永久地删除模型
// 强制删除单个模型实例...
$flight->forceDelete(); // 强制删除所有相关模型...
$flight->history()->forceDelete();
二、集合
Collection
类提供 多种辅助函数 来处理你的 Eloquent 结果。
- 遍历 Chunk & Cursor
[Chunk]
It will "paginate" your query, this way you use less memory. (1) Uses less memory (2) It takes longer
public function getData() {
Contact::chunk(1000, function ($contacts) {
foreach ($contacts as $contact) {
//rest of your code...
}
});
}
[Cursor]
You will use PHP Generators to search your query items one by one. (1) It takes less time (2) Uses more memory
public function getData() {
foreach (Contact::cursor() as $contact) {
//rest of your code...
}
}
- 返回指定行
// 取回符合查询限制的第一个模型 ...
$flight = App\Flight::where('active', 1)->first(); $flights = App\Flight::find([1, 2, 3]);
- ‘未找到’ 处理
$model = App\Flight::findOrFail(1);
$model = App\Flight::where('legs', '>', 100)->firstOrFail();
// 用法示范
Route::get('/api/flights/{id}', function ($id) {
return App\Flight::findOrFail($id);
});
- 聚合函数
可以使用 count
、sum
、max
,和其它 查询构造器 提供的 聚合函数。
这些方法会返回适当的标量值,而不是一个完整的模型实例
$count = App\Flight::where('active', 1)->count(); $max = App\Flight::where('active', 1)->max('price');
三、控制器
- 添加一条记录
自动完成了例如对时间戳的记录。
<?php namespace App\Http\Controllers; use App\Flight;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller; class FlightController extends Controller
{
/**
* 创建一个新的航班实例。
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$flight = new Flight;
$flight->name = $request->name;
$flight->save();
}
}
- 更新 & 批量更新
$flight = App\Flight::find(1); $flight->name = 'New Flight Name';
$flight->save();
两个where并列条件,然后更新字段:delayed
App\Flight::where('active', 1)
->where('destination', 'San Diego')
->update(['delayed' => 1]);
{note} 当通过“Eloquent”批量更新时,saved
和updated
模型事件将不会被更新后的模型代替。这是因为批量更新时,模型从来没有被取回。
- 批量赋值
注意:批量赋值是有风险的,所有的 Eloquent 模型都针对批量赋值(Mass-Assignment)做了保护。
方案:$fillable
作为一个可以被批量赋值的属性「白名单」;$guarded 是「黑名单」,设置为空代表大门敞开。
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Flight extends Model
{
/**
* 可以被批量赋值的属性。
* 使Flight
模型的name
属性可以被批量赋值
*
* @var array
*/
protected $fillable = ['name'];
}
赋值:
$flight = App\Flight::create(['name' => 'Flight 10']); $flight->fill(['name' => 'Flight 22']);
四、查询作用域
- 编写 全局作用域
自定义全局作用域很简单,首先定义一个实现 Illuminate\Database\Eloquent\Scope
接口的类,该接口要求你实现一个方法:apply
。
<?php namespace App\Scopes; use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder; class AgeScope implements Scope
{
/**
* 应用作用域
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @param \Illuminate\Database\Eloquent\Model $model
* @return void
*/
public function apply(Builder $builder, Model $model)
{
return $builder->where('age', '>', 200); # select * from `users` where `age` > 200
}
}
{tip} Laravel 没有规定你需要把这些类放置于哪个文件夹,你可以*在 app
文件夹下创建 Scopes
文件夹来存放。
- 应用全局作用域
<?php namespace App; use App\Scopes\AgeScope;
use Illuminate\Database\Eloquent\Model; class User extends Model
{
/**
* 数据模型的启动方法
*
* @return void
*/
protected static function boot() # 需要重写给定模型的 boot 方法
{
parent::boot();
static::addGlobalScope(new AgeScope); # 并使用addGlobalScope
方法
}
}
添加作用域后,如果使用 User::all()
查询则会生成如下SQL语句:select * from `users` where `age` > 200
- 匿名的全局作用域
Eloquent 还允许我们使用闭包定义全局作用域,这在实现简单作用域的时候特别有用,这样的话,我们就没必要定义一个单独的类。
<?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('age')->get(); User::withoutGlobalScope(AgeScope::class)->get(); // 移除多个
User::withoutGlobalScopes([FirstScope::class, SecondScope::class])->get();
- 本地作用域
本地作用域允许我们定义通用的约束集合以便在应用中复用。
例如,你可能经常需要获取最受欢迎的用户,要定义这样的一个作用域,只需在对应 Eloquent 模型方法前加上一个 scope
前缀,作用域总是返回查询构建器:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class User extends Model
{
/**
* 限制查询只包括受欢迎的用户。
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopePopular($query)
{
return $query->where('votes', '>', 100);
} /**
* 限制查询只包括活跃的用户。
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeActive($query)
{
return $query->where('active', 1);
}
}
Then, 利用查询范围
一旦定义了范围,则可以在查询模型时调用范围方法。在进行方法调用时不需要加上 scope
前缀。你甚至可以链式调用不同的范围,如:
$users = App\User::popular()->active()->orderBy('created_at')->get();
- 动态范围
定义一个可接受参数的范围。
这时只需给你的范围加上额外的参数即可。范围参数应该被定义在 $query
参数之后:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class User extends Model
{
/**
* 限制查询只包括指定类型的用户。
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeOfType($query, $type)
{
return $query->where('type', $type);
}
}
在范围调用时传递参数:
$users = App\User::ofType('admin')->get();
五、事件
- 模型的事件映射
事件让你每当有特定的模型类在数据库保存或更新时,执行代码。
Eloquent 模型会触发许多事件,让你在模型的生命周期的多个时间点进行监控:creating
, created
, updating
, updated
, saving
, saved
, deleting
, deleted
, restoring
, restored。
举例子:
当一个新模型被初次保存将会触发 creating
以及 created
事件。
如果一个模型已经存在于数据库且调用了 save
方法,将会触发 updating
和 updated
事件。
在这两种情况下都会触发 saving
和 saved
事件。
<?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 $events = [
'saved' => UserSaved::class,
'deleted' => UserDeleted::class,
];
}
- 观察者
如果你在一个给定的模型中监听许多事件,您可以使用观察者将所有监听器变成一个类。
观察者类里的方法名应该反映Eloquent想监听的事件。 每种方法接收 model 作为其唯一的参数。
Laravel不包括观察者默认目录,所以你可以创建任何你喜欢你的目录来存放:
<?php namespace App\Observers; use App\User; class UserObserver
{
/**
* 监听用户创建的事件。
*
* @param User $user
* @return void
*/
public function created(User $user)
{
//
} /**
* 监听用户删除事件。
*
* @param User $user
* @return void
*/
public function deleting(User $user)
{
//
}
}
在AppServiceProvider
注册观察者
<?php namespace App\Providers; use App\User;
use App\Observers\UserObserver;
use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider
{
/**
* 运行所有应用.
*
* @return void
*/
public function boot()
{
User::observe(UserObserver::class);
} /**
* 注册服务提供.
*
* @return void
*/
public function register()
{
//
}
}
Ref: Laravel 数据库之:数据库请求构建器【日后继续补充】