从数据库请求数据时,模型将主要使用 get 或 first 方法检索值,分别取决于您是希望检索多个模型还是检索单个模型。派生自模型的查询将返回 October\Rain\Database\Builder 的一个实例。
一旦你创建了一个模型和它关联的数据库表,你就可以开始从数据库中检索数据了。将每个模型视为一个强大的查询构建器,它允许你查询与该模型关联的数据库表。
$flights = Flight::all();如果你有一个模型实例,你可以通过访问对应的属性来访问模型的列值。例如,让我们遍历查询返回的每个 Flight 实例并输出 name 列的值。
foreach ($flights as $flight) {
echo $flight->name;
}该 all 方法将返回模型表中所有结果。由于每个模型都充当一个 查询构建器,您还可以向查询添加约束,然后使用 get 方法检索结果:
$flights = Flight::where('active', 1)
->orderBy('name', 'desc')
->take(10)
->get();由于模型是查询构建器,您应该熟悉查询构建器上所有可用的方法。您可以在模型查询中使用这些方法中的任何一种。
:::
对于像 all 和 get 这样检索多个结果的方法,将返回一个 Collection 实例。这个类提供了 多种实用方法 来处理你的结果。当然,你可以像数组一样简单地遍历这个集合。
foreach ($flights as $flight) {
echo $flight->name;
}如果你需要处理数千条记录,请使用 chunk 命令。 chunk 方法将检索一批模型,然后将它们交给一个指定的 Closure 进行处理。 使用 chunk 方法在处理大型结果集时将节省内存。
Flight::chunk(200, function ($flights) {
foreach ($flights as $flight) {
//
}
});传递给方法的第一个参数是你希望每个“块”接收的记录数。作为第二个参数传递的闭包将为从数据库中检索到的每个块调用。
除了检索给定表的所有记录,你还可以使用 find 和 first 检索单条记录。这些方法不会返回模型集合,而是返回单个模型实例。
// Retrieve a model by its primary key
$flight = Flight::find(1);
// Retrieve the first model matching the query constraints
$flight = Flight::where('active', 1)->first();有时你可能希望在找不到模型时抛出一个异常。这在路由或控制器中特别有用。findOrFail 和 firstOrFail 方法将检索查询的第一个结果。然而,如果找不到任何结果,一个 Illuminate\Database\Eloquent\ModelNotFoundException 将被抛出。
$model = Flight::findOrFail(1);
$model = Flight::where('legs', `>`, 100)->firstOrFail();当 开发 API, 如果未捕获到异常, 404 HTTP 响应将自动发送回用户, 因此在使用这些方法时, 无需编写显式检查来返回 404 响应.
Route::get('/api/flights/{id}', function ($id) {
return Flight::findOrFail($id);
});您也可以使用 count, sum, max, 以及其他 聚合函数 由查询构建器提供的. 这些方法返回相应的标量值而不是一个完整的模型实例:
$count = Flight::where('active', 1)->count();
$max = Flight::where('active', 1)->max('price');插入和更新数据是模型的核心功能,与传统的 SQL 语句相比,这使得该过程毫不费力。
要在数据库中创建新记录,只需创建一个新的模型实例,在模型上设置属性,然后调用 save 方法:
$flight = new Flight;
$flight->name = 'Sydney to Canberra';
$flight->save();在这个例子中, 我们只需创建一个新的 Flight 模型实例, 并为其 name 属性赋值. 当我们调用 save 方法时, 一条记录将被插入到数据库中. created_at 和 updated_at 时间戳也将自动设置, 因此无需手动设置它们.
该 save 方法也可用于更新数据库中已有的模型。要更新一个模型,你应该先检索它,设置任何你想更新的属性,然后调用 save 方法。同样,该 updated_at 时间戳将自动更新,因此无需手动设置其值:
$flight = Flight::find(1);
$flight->name = 'Darwin to Adelaide';
$flight->save();更新也可以针对与给定查询匹配的任意数量的模型执行。在此示例中,所有状态为 active 且 destination 为 San Diego 的航班都将被标记为延误:
Flight::where('is_active', true)
->where('destination', 'Perth')
->update(['delayed' => true]);update 方法期望一个列和值对数组,该数组表示应更新的列。
您也可以使用 create 方法在一行中保存一个新模型。 该方法将返回插入的模型实例。 但是,在此之前,您需要为模型指定 fillable 或 guarded 属性,因为所有模型都防止了批量赋值。 请注意,fillable 和 guarded 均不影响后端表单的提交,只影响 create 或 fill 方法的使用。
批量赋值漏洞发生于当用户通过一个请求传递了一个意料之外的 HTTP 参数,并且该参数改变了你数据库中一个你未曾预料到的列。例如,一个恶意用户可能会通过一个 HTTP 请求发送一个 is_admin 参数,然后该参数被映射到你的模型的 create 方法上,从而允许用户将自己提升为管理员。
首先,你应该定义你希望进行批量赋值的模型属性。
你可以使用模型上的 $fillable 属性来完成此操作。
例如,让我们将我们 Flight 模型的 name 属性设置为可批量赋值:
class Flight extends Model
{
/**
* @var array fillable attributes that are mass assignable.
*/
protected $fillable = ['name'];
}一旦我们使这些属性可批量赋值,我们就可以使用 create 方法向数据库中插入一条新记录。create 方法会返回已保存的模型实例:
$flight = Flight::create(['name' => 'Flight 10']);虽然 $fillable 作为一个属性的“白名单”来指定哪些属性可以被批量赋值,但您也可以选择使用 $guarded。 $guarded 属性应包含一个您不希望被批量赋值的属性数组。 数组中未包含的所有其他属性都将可以被批量赋值。 因此,$guarded 的作用类似于一个“黑名单”。 当然,您应该使用 $fillable 或 $guarded 中的一个,而不是同时使用两者:
class Flight extends Model
{
/**
* The attributes that aren't mass assignable.
*
* @var array
*/
protected $guarded = ['price'];
}在上面的例子中,所有属性除了price之外都将是可批量赋值的。
有时你可能只希望实例化模型的新实例。 你可以使用 make 方法来做到这一点。 make 方法将只返回一个新实例,而不保存或创建任何内容。
$flight = Flight::make(['name' => 'Flight 10']);
// Functionally the same as...
$flight = new Flight;
$flight->fill(['name' => 'Flight 10']);还有另外两种方法可以用来通过批量赋值创建模型:firstOrCreate 和 firstOrNew。 该 firstOrCreate 方法将尝试使用给定的列/值对定位数据库记录。 如果在数据库中找不到该模型,将插入一条记录并附带给定的属性。
firstOrNew 方法类似于 firstOrCreate,它将尝试在数据库中查找与给定属性匹配的记录。但是,如果未找到模型,将返回一个新的模型实例。请注意,firstOrNew 返回的模型尚未持久化到数据库中。您需要手动调用 save 来持久化它:
// Retrieve the flight by the attributes, otherwise create it
$flight = Flight::firstOrCreate(['name' => 'Flight 10']);
// Retrieve the flight by the attributes, or instantiate a new instance
$flight = Flight::firstOrNew(['name' => 'Flight 10']);要删除模型,在模型实例上调用 delete 方法:
$flight = Flight::find(1);
$flight->delete();在上面的示例中,我们先从数据库中检索模型,然后再调用 delete 方法。但是,如果您知道模型的主键,则无需检索即可删除模型。为此,请调用 destroy 方法:
Flight::destroy(1);
Flight::destroy([1, 2, 3]);
Flight::destroy(1, 2, 3);您也可以针对一组模型运行删除查询。在此示例中,我们将删除所有被标记为非活跃的航班:
$deletedRows = Flight::where('active', 0)->delete();值得注意的是,模型事件在直接从查询中删除记录时不会触发。
作用域允许您定义一组常用的约束,这些约束可以轻松地在整个应用程序中重用。例如,您可能需要频繁地检索所有被认为是“受欢迎”的用户。要定义一个作用域,只需将 scope 作为模型方法的前缀。
class User extends Model
{
/**
* scopePopular query to only include popular users.
*/
public function scopePopular($query)
{
return $query->where('votes', `>`, 100);
}
/**
* scopeActive query to only include active users.
*/
public function scopeActive($query)
{
return $query->where('is_active', 1);
}
}一旦作用域定义完成,你可以在查询模型时调用作用域方法。然而,调用该方法时你无需包含 scope 前缀。你甚至可以链式调用多个作用域,例如:
$users = User::popular()->active()->orderBy('created_at')->get();有时你可能希望定义一个接受参数的作用域。要开始使用,只需将额外的参数添加到你的作用域中。作用域参数应该在 $query 参数之后定义:
class User extends Model
{
/**
* Scope a query to only include users of a given type.
*/
public function scopeApplyType($query, $type)
{
return $query->where('type', $type);
}
}现在,您可以在调用作用域时传递参数:
$users = User::applyType('admin')->get();