Eloquent:入门
- 简介
- 定义模型(model)
- Eloquent 模型规范
- 取出多个模型
- 取出单个模型 / 集合
- 插入更新模型
- 基本插入
- 基本更新
- 大批量赋值
- 删除模型
- 软删除
- 查询软删除的模型
- 查询范围
- 事件
简介
Laravel 所自带的 Eloquent ORM 是一个优美、简洁的 ActiveRecord 实现,用来实现数据库操作。每个数据表都有一个与之相对应的“模型(Model)”,用于和数据表交互。模型(model)帮助你在数据表中查询数据,以及向数据表内插入新的记录.
在开始之前,请务必在 config/database.php
文件中正确配置数据库的连接参数。如需更多数据库配置方面的信息,请查看此文档。
定义模型(model)
开始讲解前,我们先来创建一个 Eloquent 模型(model)。模型(model)文件通常被放在app
目录下,但是,你也可以将其放置于任何地方,只要能够通过 composer.json
配置文件自动加载即可。所有的 Eloquent 模型(model)都继承自 IlluminateDatabaseEloquentModel
类。
创建一个模型(model)实例的最简单方法是使用 Artisan 命令行工具 的 make:model
指令:
php artisan make:model User
如果你希望在生成模型(model)的同时生成 数据库将迁移 ,可以通过添加 --migration
或 -m
参数来实现:
php artisan make:model User --migration
php artisan make:model User -m
Eloquent 模型规范
现在,让我们来看一个 Flight
模型类(model class),我们用它从 flights
数据表中存取信息:
数据表的表名
注意,我们并没有告诉 Eloquent 将 Flight
模型(model)和哪个数据表进行关联。默认的规则是:类名的复数形式用来当做数据表的表名,除非明确指定另一个名称。所以,在这种情况下,Eloquent 将自动推导出 Flight
模型与 flights
数据表关联。你可以在模型(model)中定义一个 table
属性,用来指定另一个数据表名称:
<?php
namespace App;
use IlluminateDatabaseEloquentModel;
class Flight extends Model
{
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'my_flights';
}
主键
Eloquent will also assume that each table has a primary key column named id
. You may define a $primaryKey
property to override this convention. Eloquent 假定每一个数据表中都存在一个命名为 id
的列作为主键。你可以通过定义一个 $primaryKey
属性来明确指定一个主键。
时间戳
默认情况下,Eloquent 期望数据表中存在 created_at
和 updated_at
字段。如果你不希望由 Eloquent 来管理这两个字段,可以在模型(model)中将 $timestamps
属性设置为 false
:
<?php
namespace App;
use IlluminateDatabaseEloquentModel;
class Flight extends Model
{
/**
* Indicates if the model should be timestamped.
*
* @var bool
*/
public $timestamps = false;
}
如果你需要定制时间戳的格式,可以通过在模型(model)中设置 $dateFormat
属性来实现。这个属性决定了日期属性如何在数据库中存储,也决定当模型(model)被序列化为数组 或者 JSON 格式时日期属性的格式:
<?php
namespace App;
use IlluminateDatabaseEloquentModel;
class Flight extends Model
{
/**
* The storage format of the model's date columns.
*
* @var string
*/
protected $dateFormat = 'U';
}
获取多个模型
一旦你创建了一个模型(model)并将其关联到了一个数据表,你就可以从数据库中获取数据了。将每一个 Eloquent 模型(model)想象为一个强大的查询构造器,该查询构造器能够帮你通过模型(model)从数据库中查询需要的数据。例如:
<?php
namespace AppHttpControllers;
use AppFlight;
use AppHttpControllersController;
class FlightController extends Controller
{
/**
* Show a list of all available flights.
*
* @return Response
*/
public function index()
{
$flights = Flight::all();
return view('flight.index', ['flights' => $flights]);
}
}
获取字段的值
对于任何一个 Eloquent 模型(model)实例,都可以将字段名当做模型(model)的属性,从而相对应的属性来获取对应的字段的 值,例如,我们将查询之后获得的所有 Flight
实例挨个遍历,并且输出每个实例的 name
字段的值:
foreach ($flights as $flight) {
echo $flight->name;
}
添加额外的束缚
The Eloquent all
method will return all of the results in the model's table. Since each Eloquent model serves as a query builder, you may also add constraints to queries, and then use the get
method to retrieve the results:
Eloquent的 all 方法将返回所有的模型数据表里的内容, 因为每个Eloquent模型代表一个查询构建器,你可以给查询添加约束, 然后使用get方法来取得结果。
$flights = AppFlight::where('active', 1)
->orderBy('name', 'desc')
->take(10)
->get();
注意: 每个Eloquent模型都是查询构建器, 你应该查看构建器所有可用的方法, 你也可以使用Eloquent查询中任何这些方法。
集合
For Eloquent methods like all
and get
which retrieve multiple results, an instance ofIlluminateDatabaseEloquentCollection
will be returned. The Collection
class provides a variety of helpful methods for working with your Eloquent results. Of course, you may simply loop over this collection like an array:
因为Eloquent方法像 all 和 get 提取很多结果, 一个IlluminateDatabaseEloquentCollection
实例将被返回,这个集合类提供了众多的帮助方法来对你的Eloquent结果惊醒加工,当然,你可以简单的遍历整个集合像一个数组一样。
foreach ($flights as $flight) {
echo $flight->name;
}
分块取出结果
If you need to process thousands of Eloquent records, use the chunk
command. Thechunk
method will retrieve a "chunk" of Eloquent models, feeding them to a givenClosure
for processing. Using the chunk
method will conserve memory when working with large result sets:
如果你需要处理上千条Eloquent查询结果, 使用chunk 方法, chunk方法将取出Eloquent模型的一块, 把它们丢给一个给定的闭包来处理。 使用chunk方法在处理大量数据集的时候将节省内存。
Flight::chunk(200, function ($flights) {
foreach ($flights as $flight) {
//
}
});
The first argument passed to the method is the number of records you wish to receive per "chunk". The Closure passed as the second argument will be called for each chunk that is retrieved from the database.
传递到方法里的第一个引数是你希望取得区块的大小, 闭包作为第二个引数,将对每个从数据库中取得的区块进行调用。
#取得单个模型,和集合
Of course, in addition to retrieving all of the records for a given table, you may also retrieve single records using find
and first
. Instead of returning a collection of models, these methods return a single model instance:
当然, 在取出一个表的所有记录之外, 你可能也能使用 find,和first取出一条记录, 不是返回一个集合的模型, 这些方法返回一个单独模型实例:
// Retrieve a model by its primary key...
$flight = AppFlight::find(1);
// Retrieve the first model matching the query constraints...
$flight = AppFlight::where('active', 1)->first();
找不到记录异常
Sometimes you may wish to throw an exception if a model is not found. This is particularly useful in routes or controllers. The findOrFail
and firstOrFail
methods will retrieve the first result of the query. However, if no result is found, aIlluminateDatabaseEloquentModelNotFoundException
will be thrown:
有时候如果记录找不到你可能会希望抛出异常, 这在路由和控制器里是特别有用,findOrfail 或 firstOrFail 方法会取得查询的第一个结果,但是,如果没有结果被找到, 一个IlluminateDatabaseEloquentModelNotFoundException 会被抛出。
$model = AppFlight::findOrFail(1);
$model = AppFlight::where('legs', '>', 100)->firstOrFail();
If the exception is not caught, a 404
HTTP response is automatically sent back to the user, so it is not necessary to write explicit checks to return 404
responses when using these methods:
如果异常被捕捉,一个404 HTTP响应会自动发送给用户,因此不需要写特别的对使用这些方法的检查。
Route::get('/api/flights/{id}', function ($id) {
return AppFlight::findOrFail($id);
});
返回集合
Of course, you may also use the query builder aggregate functions such as count
, sum
,max
, and the other aggregate functions provided by the query builder. These methods return the appropriate scalar value instead of a full model instance:
当然你可以使用查询构建器的集合方法,像是count, sum, max, 和其他查询构建器提供的的集合方法, 这些方法返回合适的 标量值而不是一个模型实例:
$count = AppFlight::where('active', 1)->count();
$max = AppFlight::where('active', 1)->max('price');
#插入和更新模型
基本的插入操作
如需在数据库中新建一条记录,只要简单地新建一个模型(model)实例,然后为此实例设置属性,最后调用 save
方法:
<?php
namespace AppHttpControllers;
use AppFlight;
use IlluminateHttpRequest;
use AppHttpControllersController;
class FlightController extends Controller
{
/**
* Create a new flight instance.
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
// Validate the request...
$flight = new Flight;
$flight->name = $request->name;
$flight->save();
}
}
在上面这个例子中,我们把通过 HTTP 请求传进来的 name
参数直接赋值给 AppFlight
模型实例的 name
属性。当我们调用 save
方法时就会向数据库中插入一条记录。当调用 save
方法时created_at
和 updated_at
时间戳就会被自动更新,不需要我们自己动手。
基本的更新操作
save
方法可以用于更新数据库中已经存在的模型(model)。为了更新一个模型(model),首先你必须从数据库中将其取出,然后为需要更新的属性赋值,最后调用 save
方法。此外,updated_at
时间戳会被自动更新,所以不需要手动设置 updated_at
的值:
$flight = AppFlight::find(1);
$flight->name = 'New Flight Name';
$flight->save();
Updates can also be performed against any number of models that match a given query. In this example, all flights that are active
and have a destination
of San Diego
will be marked as delayed:
更新操作也可以在符合指定查询条件的多个模型实例上进行。在下面例子中,所有标记为 active
并且 destination
是 San Diego
的飞机都被标记为延时:
AppFlight::where('active', 1)
->where('destination', 'San Diego')
->update(['delayed' => 1]);
传递给 update
方法的参数必须是一个数组,数组中包含的是一系列键值对,分别对应需要更新的字段名称和更新后的值。
批量赋值
You may also use the create
method to save a new model in a single line. The inserted model instance will be returned to you from the method. However, before doing so, you will need to specify either a fillable
or guarded
attribute on the model, as all Eloquent models protect against mass-assignment.
A mass-assignment vulnerability occurs when user's pass unexpected HTTP parameters through a request, and then that parameter changes a column in your database you did not expect. For example, a malicious user might send an is_admin
parameter through an HTTP request, which is then mapped onto your model's create
method, allowing the user to escalate themselves to an administrator.
So, to get started, you should define which model attributes you want to make mass assignable. You may do this using the $fillable
property on the model. For example, let's make the name
attribute of our Flight
model mass assignable:
你也可以使用create方法在新的一行来保存新的模型, 这个被插入的模型实例将从方法被返回,然而,在做这个之前你需要在模型中指定 fillable 或 guarded 属性, 所有Eloquent 模型都保护批量赋值。
<?php
namespace App;
use IlluminateDatabaseEloquentModel;
class Flight extends Model
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['name'];
}
Once we have made the attributes mass assignable, we can use the create
method to insert a new record in the database. The create
method returns the saved model instance:
一旦你可以对属性批量赋值, 你可以用create方法来插入对数据库插入新纪录, create方法返回保存的模型实例。
$flight = AppFlight::create(['name' => 'Flight 10']);
While $fillable
serves as a "white list" of attributes that should be mass assignable, you may also choose to use $guarded
. The $guarded
property should contain an array of attributes that you do not want to be mass assignable. All other attributes not in the array will be mass assignable. So, $guarded
functions like a "black list". Of course, you should use either $fillable
or $guarded
- not both:
当 $fillable 充当一个可以批量赋值的白名单, 你可能回选择使用 $guarded. $guarded 属性应该包含一个你不想被批量赋值属性数组,所有其他不在数组中的属性将是可以批量赋值的, 因此,$guarded 方法就像一个“黑名单”。当然你应该或者使用$fillable 或者使用 $guarded ,而不是两个都用。
<?php
namespace App;
use IlluminateDatabaseEloquentModel;
class Flight extends Model
{
/**
* The attributes that aren't mass assignable.
*
* @var array
*/
protected $guarded = ['price'];
}
In the example above, all attributes except for price
will be mass assignable.
在以上的例子中,除了price之外的属性都可以批量赋值。
其他Create方法
There are two other methods you may use to create models by mass assigning attributes: firstOrCreate
and firstOrNew
. The firstOrCreate
method will attempt to locate a database record using the given column / value pairs. If the model can not be found in the database, a record will be inserted with the given attributes.
The firstOrNew
method, like firstOrCreate
will attempt to locate a record in the database matching the given attributes. However, if a model is not found, a new model instance will be returned. Note that the model returned by firstOrNew
has not yet been persisted to the database. You will need to call save
manually to persist it:
还有两个其他方法你可以用来批量创建模型,firstOrCreate 和 firstOrNew。 当firstOrCreate 方法视图通过给出的 字段/值对 定位数据库记录, 如果记录找不到,一个给定属性的记录将会被插入。
// Retrieve the flight by the attributes, or create it if it doesn't exist...
$flight = AppFlight::firstOrCreate(['name' => 'Flight 10']);
// Retrieve the flight by the attributes, or instantiate a new instance...
$flight = AppFlight::firstOrNew(['name' => 'Flight 10']);
删除模型
To delete a model, call the delete
method on a model instance:
要删除模型,对model实例的delete方法将被调用。
$flight = AppFlight::find(1);
$flight->delete();
用键值删除现有实例
In the example above, we are retrieving the model from the database before calling thedelete
method. However, if you know the primary key of the model, you may delete the model without retrieving it. To do so, call the destroy
method:
在 上面的例子,我们在调用delete方法的时候要取出数据库里的模型实例,然而,如果你知道一个模型的主键, 你可以删除模型而不需要取出它,要这样做,调用destroy方法。
AppFlight::destroy(1);
AppFlight::destroy([1, 2, 3]);
AppFlight::destroy(1, 2, 3);
通过查询删除模型
Of course, you may also run a delete query on a set of models. In this example, we will delete all flights that are marked as inactive:
当然,你可以通过对模型运行一个删除语句,这个例子中,我们将删除所有标记为inactive的flights
$deletedRows = AppFlight::where('active', 0)->delete();
软删除
In addition to actually removing records from your database, Eloquent can also "soft delete" models. When models are soft deleted, they are not actually removed from your database. Instead, a deleted_at
attribute is set on the model and inserted into the database. If a model has a non-null deleted_at
value, the model has been soft deleted. To enable soft deletes for a model, use the IlluminateDatabaseEloquentSoftDeletes
trait on the model and add the deleted_at
column to your $dates
property:
除了从数据库删除记录, Eloquent还可以用来“软删除”模型,当模型被软删除,他们并不会从数据库被删除。 相反,一个 deleted_at属性被设置,如果数据模型有个非空的deleted_at值,这个模型就会被软删除,要使得软删除可以实现,在模型定义里使用 IlluminateDatabaseEloquentSoftDeletes
特性,添加deleted_at 字段到$dates 属性。
<?php
namespace App;
use IlluminateDatabaseEloquentModel;
use IlluminateDatabaseEloquentSoftDeletes;
class Flight extends Model
{
use SoftDeletes;
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $dates = ['deleted_at'];
}
Of course, you should add the deleted_at
column to your database table. The Laravelschema builder contains a helper method to create this column:
当然,你应该添加deleted_at 字段到数据库表, Laravel 模式构建器包含一个帮助方法去添加这个字段。
Schema::table('flights', function ($table) {
$table->softDeletes();
});
Now, when you call the delete
method on the model, the deleted_at
column will be set to the current date and time. And, when querying a model that uses soft deletes, the soft deleted models will automatically be excluded from all query results.
现在当你在模型上调用 delete方法, deleted_at字段会被设置成为当前日期和时间, 当查询一个含有软删除记录的模型,那些被软删除的记录会自动从查询结果中被排除。
To determine if a given model instance has been soft deleted, use the trashed
method:
要验证一个给定的模型实例是否已经被软删除,使用trashed 方法。
if ($flight->trashed()) {
//
}
#查询被软删除的记录
查询结果包括被软删除的记录
As noted above, soft deleted models will automatically be excluded from query results. However, you may force soft deleted models to appear in a result set using thewithTrashed
method on the query:
就像上面提到的, 软删除模型自动地被从查询结果中排除, 然而,你可以强制软删除后的模型出现在结果集,你可以在查询中使用withTrashed 方法:
$flights = AppFlight::withTrashed()
->where('account_id', 1)
->get();
The withTrashed
method may also be used on a relationship query:
withTrashed方法也能被用于关系查询中。
$flight->history()->withTrashed()->get();
只取出软删除记录
The onlyTrashed
method will retrieve only soft deleted models:
onlyTrashed方法将只取出软删除后的记录。
$flights = AppFlight::onlyTrashed()
->where('airline_id', 1)
->get();
恢复软删除记录
Sometimes you may wish to "un-delete" a soft deleted model. To restore a soft deleted model into an active state, use the restore
method on a model instance:
有时候你可能希望去“反-删除”一个软删除的模型,要恢复模型到有效状态,使用restore方法。
$flight->restore();
You may also use the restore
method in a query to quickly restore multiple models:
你也可以在一个查询中快速恢复多个模型使用restore方法。
AppFlight::withTrashed()
->where('airline_id', 1)
->restore();
Like the withTrashed
method, the restore
method may also be used on relationships:
就像withTrashed方法,restore方法也可以用在关系查询。
$flight->history()->restore();
永久删除模型
Sometimes you may need to truly remove a model from your database. To permanently remove a soft deleted model from the database, use the forceDelete
method:
有时你需要从数据库中真正删除一个模型,要永久删除一个软删除模型,使用forceDelete 方法
// Force deleting a single model instance...
$flight->forceDelete();
// Force deleting all related models...
$flight->history()->forceDelete();
#范围查询
Scopes allow you to define common sets of constraints that you may easily re-use throughout your application. For example, you may need to frequently retrieve all users that are considered "popular". To define a scope, simply prefix an Eloquent model method with scope
:
范围允许你定义一套约束你可以方便地重用, 例如你需要经常取出所有被认为是“popular”的用户, 要定义这个范围,只要在Eloquent模型方法前加上scope。
<?php
namespace App;
use IlluminateDatabaseEloquentModel;
class User extends Model
{
/**
* Scope a query to only include popular users.
*
* @return IlluminateDatabaseEloquentBuilder
*/
public function scopePopular($query)
{
return $query->where('votes', '>', 100);
}
/**
* Scope a query to only include active users.
*
* @return IlluminateDatabaseEloquentBuilder
*/
public function scopeActive($query)
{
return $query->where('active', 1);
}
}
利用查询范围
Once the scope has been defined, you may call the scope methods when querying the model. However, you do not need to include the scope
prefix when calling the method. You can even chain calls to various scopes, for example:
一旦范围确定,你就可以在查询模型的时候调用 范围方法, 然而,你的方法不需要包含scope前缀,你甚至可以链接不通范围的调用,例如。
$users = AppUser::popular()->women()->orderBy('created_at')->get();
动态范围
$query
argument:<?php
namespace App;
use IlluminateDatabaseEloquentModel;
class User extends Model
{
/**
* Scope a query to only include users of a given type.
*
* @return IlluminateDatabaseEloquentBuilder
*/
public function scopeOfType($query, $type)
{
return $query->where('type', $type);
}
}
Now, you may pass the parameters when calling the scope:
现在,你可以在调用scope方法的时候传递参数。
$users = AppUser::ofType('admin')->get();
事件
Eloquent models fire several events, allowing you to hook into various points in the model's lifecycle using the following methods: creating
, created
, updating
, updated
, saving
,saved
, deleting
, deleted
, restoring
, restored
. Events allow you to easily execute code each time a specific model class is saved or updated in the database.
Eloquent 模型(model)能够触发多个事件,通过调用下面所列出的方法,你可以在模型(model)的生命周期中的每个“关键点”上执行自己的代码,从而影响模型(model)的执行流程:creating
、created
、updating
、updated
、saving、
saved、
deleting、
deleted、
restoring、
restored`。每当某个模型(model)被保存或更新到数据库中时,你都能通过事件轻松地插入自己编写的代码并让它执行。
基本用法
每当一个新模型(model)头一次被保存时,都将触发 creating
和 created
事件。 如果模型(model)已经存在于数据库中,并且 save
方法被调用了,将触发 updating
/ updated
事件。无论如何,saving
/ saved
事件都会被触发。
例如,我们在一个服务提供者(service provider) 中定义一个 Eloquent 事件监听器。在我们的事件监听器中,我们要在给定的模型(model)上调用 isValid
方法,如果该模型(model)是无效的,则返回 false
。如果 Eloquent 事件监听器中返回的是 false
,将取消 save
/ update
操作:
<?php
namespace AppProviders;
use AppUser;
use IlluminateSupportServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
User::creating(function ($user) {
if ( ! $user->isValid()) {
return false;
}
});
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
//
}
}