首页 后端开发 php教程 [ Laravel 5.2 文档 ] Eloquent ORM -- 起步

[ Laravel 5.2 文档 ] Eloquent ORM -- 起步

May 25, 2018 pm 04:24 PM

1、简介

Laravel自带的 EloquentORM 提供了一个美观、简单的与数据库打交道的 ActiveRecord 实现,每张数据表都对应一个与该表进行交互的“模型”,模型允许你在表中进行数据查询,以及插入、 更新、删除等操作。

在开始之前,确保在 config/database.php文件中配置好了数据库连接。更多关于数据库配置的信息,请查看文档。

2、定义模型

作为开始,让我们创建一个 Eloquent 模型,模型通常位于 app目录下,你也可以将其放在其他可以被 composer.json文件自动加载的地方。所有Eloquent模型都继承自 Illuminate\Database\Eloquent\Model类。

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

php artisan make:model User

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

php artisan make:model User --migrationphp artisan make:model User -m

Eloquent 模型约定

现在,让我们来看一个 Flight模型类例子,我们将用该类获取和存取数据表 flights中的信息:

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Flight extends Model{    //}
登录后复制

表名

注意我们并没有告诉 Eloquent 我们的 Flight模型使用哪张表。默认规则是模型类名的复数作为与其对应的表名,除非在模型类中明确指定了其它名称。所以,在本例中,Eloquent 认为 Flight模型存储记录在 flights表中。你也可以在模型中定义 table属性来指定自定义的表名:

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Flight extends Model{    /**     * 关联到模型的数据表     *     * @var string     */    protected $table = &#39;my_flights&#39;;}
登录后复制

主键

Eloquent 默认每张表的主键名为 id,你可以在模型类中定义一个 $primaryKey属性来覆盖该约定。

时间戳

默认情况下,Eloquent 期望 created_at和 updated_at已经存在于数据表中,如果你不想要这些 Laravel 自动管理的列,在模型类中设置 $timestamps属性为 false:

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

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Flight extends Model{    /**     * 模型日期列的存储格式     *     * @var string     */    protected $dateFormat = &#39;U&#39;;}
登录后复制

数据库连接

默认情况下,所有的 Eloquent 模型使用应用配置中的默认数据库连接,如果你想要为模型指定不同的连接,可以通过 $connection属性来设置:

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Flight extends Model{    /**     * The connection name for the model.     *     * @var string     */    protected $connection = &#39;connection-name&#39;;}
登录后复制

3、获取多个模型

创建完模型及其关联的数据表后,就要准备从数据库中获取数据。将Eloquent模型看作功能强大的查询构建器,你可以使用它来流畅的查询与其关联的数据表。例如:

<?phpnamespace App\Http\Controllers;use App\Flight;use App\Http\Controllers\Controller;class FlightController extends Controller{    /**     * 显示所有有效航班列表     *     * @return Response     */    public function index()    {        $flights = Flight::all();        return view(&#39;flight.index&#39;, [&#39;flights&#39; => $flights]);    }}
登录后复制

访问列值

如果你有一个 Eloquent 模型实例,可以通过访问其相应的属性来访问模型的列值。例如,让我们循环查询返回的每一个 Flight实例并输出 name的值:

foreach ($flights as $flight) {    echo $flight->name;}
登录后复制
登录后复制

添加额外约束

Eloquent 的 all方法返回模型表的所有结果,由于每一个Eloquent模型都是一个查询构建器,你还可以添加约束条件到查询,然后使用 get方法获取对应结果:

$flights = App\Flight::where(&#39;active&#39;, 1)               ->orderBy(&#39;name&#39;, &#39;desc&#39;)               ->take(10)               ->get();
登录后复制

注意:由于 Eloquent 模型本质上就是查询构建器,你可以在Eloquent查询中使用查询构建器的所有方法。

集合

对 Eloquent 中获取多个结果的方法(比如 all和 get)而言,其返回值是 Illuminate\Database\Eloquent\Collection的一个实例, Collection类提供了多个有用的函数来处理Eloquent结果。当然,你可以像操作数组一样简单循环这个集合:

foreach ($flights as $flight) {    echo $flight->name;}
登录后复制
登录后复制

组块结果集

如果你需要处理成千上万个 Eloquent 结果,可以使用 chunk命令。 chunk方法会获取一个“组块”的 Eloquent 模型,并将其填充到给定闭包进行处理。使用 chunk方法能够在处理大量数据集合时有效减少内存消耗:

Flight::chunk(200, function ($flights) {    foreach ($flights as $flight) {        //    }});
登录后复制

传递给该方法的第一个参数是你想要获取的“组块”数目,闭包作为第二个参数被调用用于处理每个从数据库获取的区块数据。

4、获取单个模型/聚合

当然,除了从给定表中获取所有记录之外,还可以使用 find和 first获取单个记录。这些方法返回单个模型实例而不是返回模型集合:

// 通过主键获取模型...$flight = App\Flight::find(1);// 获取匹配查询条件的第一个模型...$flight = App\Flight::where('active', 1)->first();

Not Found 异常

有时候你可能想要在模型找不到的时候抛出异常,这在路由或控制器中非常有用, findOrFail和 firstOrFail方法会获取查询到的第一个结果。然而,如果没有任何查询结果, Illuminate\Database\Eloquent\ModelNotFoundException异常将会被抛出:

$model = App\Flight::findOrFail(1);$model = App\Flight::where(&#39;legs&#39;, &#39;>&#39;, 100)->firstOrFail();
登录后复制

如果异常没有被捕获,那么HTTP 404 响应将会被发送给用户,所以在使用这些方法的时候没有必要对返回404响应编写明确的检查:

Route::get(&#39;/api/flights/{id}&#39;, function ($id) {    return App\Flight::findOrFail($id);});
登录后复制

获取聚合

当然,你还可以使用查询构建器聚合方法,例如 count、 sum、 max,以及其它查询构建器提供的聚合方法。这些方法返回计算后的结果而不是整个模型实例:

$count = App\Flight::where(&#39;active&#39;, 1)->count();$max = App\Flight::where(&#39;active&#39;, 1)->max(&#39;price&#39;);
登录后复制

5、插入/更新模型

基本插入

想要在数据库中插入新的记录,只需创建一个新的模型实例,设置模型的属性,然后调用 save方法:

<?phpnamespace 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)    {        // Validate the request...        $flight = new Flight;        $flight->name = $request->name;        $flight->save();    }}
登录后复制

在这个例子中,我们只是简单分配HTTP请求中的 name参数值给 App\Flight模型实例的那么属性,当我们调用 save方法时,一条记录将会被插入数据库。 created_at和 updated_at时间戳在 save方法被调用时会自动被设置,所以没必要手动设置它们。

基本更新

save方法还可以用于更新数据库中已存在的模型。要更新一个模型,应该先获取它,设置你想要更新的属性,然后调用 save方法。同样, updated_at时间戳会被自动更新,所以没必要手动设置其值:

$flight = App\Flight::find(1);$flight->name = &#39;New Flight Name&#39;;$flight->save();
登录后复制

更新操作还可以同时修改给定查询提供的多个模型实例,在本例中,所有有效且 destination=San Diego的航班都被标记为延迟:

App\Flight::where(&#39;active&#39;, 1)          ->where(&#39;destination&#39;, &#39;San Diego&#39;)          ->update([&#39;delayed&#39; => 1]);
登录后复制

update方法要求以数组形式传递键值对参数,代表着数据表中应该被更新的列。

批量赋值

还可以使用 create方法保存一个新的模型。该方法返回被插入的模型实例。但是,在此之前,你需要指定模型的 fillable或 guarded属性,因为所有Eloquent模型都通过批量赋值(Mass Assignment)进行保护。

当用户通过 HTTP 请求传递一个不被期望的参数值时就会出现安全隐患,然后该参数以不被期望的方式修改数据库中的列值。例如,恶意用户通过 HTTP 请求发送一个 is_admin参数,然后该参数映射到模型的 create方法,从而允许用户将自己变成管理员。

所以,你应该在模型中定义哪些属性是可以进行赋值的,使用模型上的 $fillable属性即可实现。例如,我们设置 Flight模型上的 name属性可以被赋值:

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Flight extends Model{    /**     * 可以被批量赋值的属性.     *     * @var array     */    protected $fillable = [&#39;name&#39;];}
登录后复制

设置完可以被赋值的属性之后,我们就可以使用 create方法在数据库中插入一条新的记录。 create方法返回保存后的模型实例:

$flight = App\Flight::create([&#39;name&#39; => &#39;Flight 10&#39;]);
登录后复制

$fillable就像是可以被赋值属性的“白名单”,还可以选择使用 $guarded。 $guarded属性包含你不想被赋值的属性数组。所以不被包含在其中的属性都是可以被赋值的,因此,$guarded方法就像“黑名单”。当然,你只能同时使用其中一个——而不是一起使用:

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Flight extends Model{    /**     * 不能被批量赋值的属性     *     * @var array     */    protected $guarded = [&#39;price&#39;];}
登录后复制

在这个例子中,除了 $price之外的所有属性都是可以被赋值的。

其它创建方法

还有其它两种可以用来创建模型的方法: firstOrCreate和 firstOrNew。 firstOrCreate方法先尝试通过给定列/值对在数据库中查找记录,如果没有找到的话则通过给定属性创建一个新的记录。

firstOrNew方法和 firstOrCreate方法一样先尝试在数据库中查找匹配的记录,如果没有找到,则返回一个的模型实例。注意通过 firstOrNew方法返回的模型实例并没有持久化到数据库中,你还需要调用 save方法手动持久化:

// 通过属性获取航班, 如果不存在则创建...$flight = App\Flight::firstOrCreate([&#39;name&#39; => &#39;Flight 10&#39;]);// 通过属性获取航班, 如果不存在初始化一个新的实例...$flight = App\Flight::firstOrNew([&#39;name&#39; => &#39;Flight 10&#39;]);
登录后复制

6、删除模型

要删除一个模型,调用模型实例上的 delete方法:

$flight = App\Flight::find(1);$flight->delete();
登录后复制

通过主键删除模型

在上面的例子中,我们在调用 delete方法之前从数据库中获取该模型,然而,如果你知道模型的主键的话,可以调用destroy方法直接删除而不需要获取它:

App\Flight::destroy(1);App\Flight::destroy([1, 2, 3]);App\Flight::destroy(1, 2, 3);
登录后复制

通过查询删除模型

当然,你还可以通过查询删除多个模型,在本例中,我们删除所有被标记为无效的航班:

$deletedRows = App\Flight::where(&#39;active&#39;, 0)->delete();
登录后复制

软删除

除了从数据库删除记录外,Eloquent还可以对模型进行“软删除”。当模型被软删除后,它们并没有真的从数据库删除,而是在模型上设置一个 deleted_at属性并插入数据库,如果模型有一个非空 deleted_at值,那么该模型已经被软删除了。要启用模型的软删除功能,可以使用模型上的 Illuminate\Database\Eloquent\SoftDeletestrait并添加 deleted_at列到 $dates属性:

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\SoftDeletes;class Flight extends Model{    use SoftDeletes;    /**     * 应该被调整为日期的属性     *     * @var array     */    protected $dates = [&#39;deleted_at&#39;];}
登录后复制

当然,应该添加 deleted_at列到数据表。Laravel Schema构建器包含一个帮助函数来创建该列:

Schema::table(&#39;flights&#39;, function ($table) {    $table->softDeletes();});
登录后复制

现在,当调用模型的 delete方法时, deleted_at列将被设置为当前日期和时间,并且,当查询一个使用软删除的模型时,被软删除的模型将会自动从查询结果中排除。

判断给定模型实例是否被软删除,可以使用 trashed方法:

if ($flight->trashed()) {    //}
登录后复制

查询被软删除的模型

包含软删除模型

正如上面提到的,软删除模型将会自动从查询结果中排除,但是,如果你想要软删除模型出现在查询结果中,可以使用 withTrashed方法:

$flights = App\Flight::withTrashed()                ->where(&#39;account_id&#39;, 1)                ->get();
登录后复制

withTrashed方法也可以用于关联查询中:

$flight->history()->withTrashed()->get();
登录后复制

只获取软删除模型

onlyTrashed方法之获取软删除模型:

$flights = App\Flight::onlyTrashed()                ->where(&#39;airline_id&#39;, 1)                ->get();
登录后复制

恢复软删除模型

有时候你希望恢复一个被软删除的模型,可以使用 restore方法:

$flight->restore();
登录后复制

你还可以在查询中使用 restore方法来快速恢复多个模型:

App\Flight::withTrashed()        ->where(&#39;airline_id&#39;, 1)        ->restore();
登录后复制

和 withTrashed方法一样, restore方法也可以用于关联查询:

$flight->history()->restore();
登录后复制

永久删除模型

有时候你真的需要从数据库中删除一个模型,可以使用 forceDelete方法:

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

7、查询作用域

全局作用域

全局作用域允许我们为给定模型的所有查询添加条件约束。Laravel 自带的软删除功能就使用了全局作用域来从数据库中拉出所有没有被删除的模型。编写自定义的全局作用域可以提供一种方便的、简单的方式来确保给定模型的每个查询都有特定的条件约束。

编写全局作用域

自定义全局作用域很简单,首先定义一个实现 Illuminate\Database\Eloquent\Scope接口的类,该接口要求你实现一个方法:apply。需要的话可以在 apply方法中添加 where条件到查询:

<?phpnamespace App\Scopes;use Illuminate\Database\Eloquent\Scope;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Builder;class AgeScope implements Scope{    /**     * Apply the scope to a given Eloquent query builder.     *     * @param  \Illuminate\Database\Eloquent\Builder  $builder     * @param  \Illuminate\Database\Eloquent\Model  $model     * @return void     */    public function apply(Builder $builder, Model $model)    {        return $builder->where(&#39;age&#39;, &#39;>&#39;, 200);    }}
登录后复制

应用全局作用域

要将全局作用域分配给模型,需要重写给定模型的 boot方法并使用 addGlobalScope方法:

<?phpnamespace App;use App\Scopes\AgeScope;use Illuminate\Database\Eloquent\Model;class User extends Model{    /**     * The "booting" method of the model.     *     * @return void     */    protected static function boot()    {        parent::boot();        static::addGlobalScope(new AgeScope);    }}
登录后复制

添加作用域后,如果使用 User::all()查询则会生成如下SQL语句:

select * from `users` where `age` > 200
登录后复制

匿名的全局作用域

Eloquent还允许我们使用闭包定义全局作用域,这在实现简单作用域的时候特别有用,这样的话,我们就没必要定义一个单独的类了:

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Builder;class User extends Model{    /**     * The "booting" method of the model.     *     * @return void     */    protected static function boot()    {        parent::boot();        static::addGlobalScope(&#39;age&#39;, function(Builder $builder) {            $builder->where(&#39;age&#39;, &#39;>&#39;, 200);        });    }}
登录后复制

我们还可以通过以下方式移除全局作用:

User::withoutGlobalScope(&#39;age&#39;)->get();
登录后复制

移除全局作用域

如果想要在给定查询中移除指定全局作用域,可以使用 withoutGlobalScope:

User::withoutGlobalScope(AgeScope::class)->get();
登录后复制

如果你想要移除某几个或全部全局作用域,可以使用 withoutGlobalScopes方法:

User::withoutGlobalScopes()->get();User::withoutGlobalScopes([FirstScope::class, SecondScope::class])->get();
登录后复制

本地作用域

本地作用域允许我们定义通用的约束集合以便在应用中复用。例如,你可能经常需要获取最受欢迎的用户,要定义这样的一个作用域,只需简单在对应Eloquent模型方法前加上一个 scope前缀,作用域总是返回查询构建器:

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class User extends Model{    /**     * 只包含活跃用户的查询作用域     *     * @return \Illuminate\Database\Eloquent\Builder     */    public function scopePopular($query)    {        return $query->where(&#39;votes&#39;, &#39;>&#39;, 100);    }    /**     * 只包含激活用户的查询作用域     *     * @return \Illuminate\Database\Eloquent\Builder     */    public function scopeActive($query)    {        return $query->where(&#39;active&#39;, 1);    }}
登录后复制

使用查询作用域

作用域被定义好了之后,就可以在查询模型的时候调用作用域方法,但调用时不需要加上 scope前缀,你甚至可以在同时调用多个作用域,例如:

$users = App\User::popular()->active()->orderBy(&#39;created_at&#39;)->get();
登录后复制

动态作用域

有时候你可能想要定义一个可以接收参数的作用域,你只需要将额外的参数添加到你的作用域即可。作用域参数应该被定义在 $query参数之后:

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class User extends Model{    /**     * 只包含给用类型用户的查询作用域     *     * @return \Illuminate\Database\Eloquent\Builder     */    public function scopeOfType($query, $type)    {        return $query->where(&#39;type&#39;, $type);    }}
登录后复制

现在,你可以在调用作用域时传递参数了:

$users = App\User::ofType(&#39;admin&#39;)->get();
登录后复制

8、事件

Eloquent模型可以触发事件,允许你在模型生命周期中的多个时间点调用如下这些方法: creating, created, updating, updated, saving, saved, deleting, deleted, restoring, restored。事件允许你在一个指定模型类每次保存或更新的时候执行代码。

基本使用

一个新模型被首次保存的时候, creating和 created事件会被触发。如果一个模型已经在数据库中存在并调用 save方法, updating/updated事件会被触发,无论是创建还是更新,saving/saved事件都会被调用。

举个例子,我们在服务提供者中定义一个Eloquent事件监听器,在事件监听器中,我们会调用给定模型的 isValid方法,如果模型无效会返回 false。如果从Eloquent事件监听器中返回 false则取消 save/update操作:

<?phpnamespace App\Providers;use App\User;use Illuminate\Support\ServiceProvider;class AppServiceProvider extends ServiceProvider{    /**     * 启动所有应用服务     *     * @return void     */    public function boot()    {        User::creating(function ($user) {            if ( ! $user->isValid()) {                return false;            }        });    }    /**     * 注册服务提供者.     *     * @return void     */    public function register()    {        //    }}
登录后复制


本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
威尔R.E.P.O.有交叉游戏吗?
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

在PHP API中说明JSON Web令牌(JWT)及其用例。 在PHP API中说明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一种基于JSON的开放标准,用于在各方之间安全地传输信息,主要用于身份验证和信息交换。1.JWT由Header、Payload和Signature三部分组成。2.JWT的工作原理包括生成JWT、验证JWT和解析Payload三个步骤。3.在PHP中使用JWT进行身份验证时,可以生成和验证JWT,并在高级用法中包含用户角色和权限信息。4.常见错误包括签名验证失败、令牌过期和Payload过大,调试技巧包括使用调试工具和日志记录。5.性能优化和最佳实践包括使用合适的签名算法、合理设置有效期、

描述扎实的原则及其如何应用于PHP的开发。 描述扎实的原则及其如何应用于PHP的开发。 Apr 03, 2025 am 12:04 AM

SOLID原则在PHP开发中的应用包括:1.单一职责原则(SRP):每个类只负责一个功能。2.开闭原则(OCP):通过扩展而非修改实现变化。3.里氏替换原则(LSP):子类可替换基类而不影响程序正确性。4.接口隔离原则(ISP):使用细粒度接口避免依赖不使用的方法。5.依赖倒置原则(DIP):高低层次模块都依赖于抽象,通过依赖注入实现。

解释PHP中晚期静态结合的概念。 解释PHP中晚期静态结合的概念。 Mar 21, 2025 pm 01:33 PM

文章讨论了PHP 5.3中引入的PHP中的晚期静态结合(LSB),从而允许静态方法的运行时分辨率调用以获得更灵活的继承。 LSB的实用应用和潜在的触摸

如何用PHP的cURL库发送包含JSON数据的POST请求? 如何用PHP的cURL库发送包含JSON数据的POST请求? Apr 01, 2025 pm 03:12 PM

使用PHP的cURL库发送JSON数据在PHP开发中,经常需要与外部API进行交互,其中一种常见的方式是使用cURL库发送POST�...

框架安全功能:防止漏洞。 框架安全功能:防止漏洞。 Mar 28, 2025 pm 05:11 PM

文章讨论了框架中的基本安全功能,以防止漏洞,包括输入验证,身份验证和常规更新。

如何在系统重启后自动设置unixsocket的权限? 如何在系统重启后自动设置unixsocket的权限? Mar 31, 2025 pm 11:54 PM

如何在系统重启后自动设置unixsocket的权限每次系统重启后,我们都需要执行以下命令来修改unixsocket的权限:sudo...

自定义/扩展框架:如何添加自定义功能。 自定义/扩展框架:如何添加自定义功能。 Mar 28, 2025 pm 05:12 PM

本文讨论了将自定义功能添加到框架上,专注于理解体系结构,识别扩展点以及集成和调试的最佳实践。

See all articles