Eloquent 模型类
本页内容
概述
本指南向您展示了如何使用Laravel MongoDB来定义和自定义Laravel Eloquent模型。您可以使用这些模型通过使用Laravel Eloquent对象关系映射器(ORM)来处理MongoDB数据。
以下部分解释了如何将Laravel Eloquent ORM行为添加到Laravel MongoDB模型中
定义Eloquent模型类演示了如何创建模型类。
扩展Authenticatable模型展示了如何设置MongoDB作为认证用户提供者。
自定义Eloquent模型类解释了几个模型类的自定义。
扩展第三方模型类解释了如何使第三方模型类与MongoDB兼容。
指定修剪行为展示了如何定期删除不再需要的模型。
创建版本化模型模式展示了如何实现模型模式版本化。
定义Eloquent模型类
Eloquent模型是表示您数据的类。它们包含执行数据库操作(如插入、更新和删除)的方法。
要声明Laravel MongoDB模型,在您的Laravel应用程序的app/Models
目录中创建一个类,该类扩展MongoDB\Laravel\Eloquent\Model
,如下面的代码示例所示
namespace App\Models; use MongoDB\Laravel\Eloquent\Model; class Planet extends Model { }
默认情况下,模型使用在Laravel应用程序的config/database.php
设置中设置的MongoDB数据库名称和您的模型类名称的蛇形复数形式作为集合。
该模型存储在planets
MongoDB集合中。
提示
或者,使用 artisan
控制台来生成模型类,并将 Illuminate\Database\Eloquent\Model
导入更改为 MongoDB\Laravel\Eloquent\Model
。要了解更多关于 artisan
控制台的信息,请参阅 Laravel 文档中的 Artisan 控制台。
要了解如何指定 Laravel 应用使用的数据库名称,配置 MongoDB 连接.
扩展 Authenticatable 模型
要配置 MongoDB 作为 Laravel 用户提供者,可以扩展 Laravel 集成 MongoDB\Laravel\Auth\User
类。以下代码示例展示了如何扩展此类
namespace App\Models; use MongoDB\Laravel\Auth\User as Authenticatable; class User extends Authenticatable { }
要了解如何自定义 Laravel 身份验证用户提供者,请参阅 Laravel 文档中的 添加自定义用户提供者。
自定义Eloquent模型类
本节展示了如何进行以下Eloquent模型行为自定义
更改模型集合名称
默认情况下,模型使用模型类名的蛇形复数形式作为集合名称。要更改模型用于从MongoDB中检索和保存数据的集合名称,请覆盖模型类中的 $table
属性。
注意
建议使用默认的集合命名行为,以保持模型与集合之间的关联简单明了。
以下示例指定了自定义MongoDB集合名称 celestial_body
,用于 Planet
类
namespace App\Models; use MongoDB\Laravel\Eloquent\Model; class Planet extends Model { protected $table = 'celestial_body'; }
如果没有覆盖 $table
属性,此模型将映射到 planets
集合。使用覆盖的属性,示例类将模型存储在 celestial_body
集合中。
更改主键字段
要自定义模型的主键字段,该字段唯一标识MongoDB文档,请覆盖模型类中的 $primaryKey
属性。
默认情况下,模型使用PHP MongoDB驱动程序为Laravel应用程序插入的每个文档生成唯一的ObjectID。
以下示例指定了name
字段为Planet
类的主键。
namespace App\Models; use MongoDB\Laravel\Eloquent\Model; class Planet extends Model { protected $primaryKey = 'name'; }
要了解更多关于主键行为和自定义选项的信息,请参阅Laravel文档中的Eloquent Primary Keys。
要了解关于_id
字段、ObjectIDs以及MongoDB文档结构的信息,请参阅服务器手册中的Documents。
启用软删除
Eloquent包含了一个软删除功能,它改变了模型中delete()
方法的行为。当模型上启用了软删除时,delete()
方法将文档标记为已删除,而不是从数据库中删除它。它会在deleted_at
字段上设置时间戳,以自动将其排除在检索操作之外。
要在类上启用软删除,请按照以下代码示例添加MongoDB\Laravel\Eloquent\SoftDeletes
特质。
namespace App\Models; use MongoDB\Laravel\Eloquent\Model; use MongoDB\Laravel\Eloquent\SoftDeletes; class Planet extends Model { use SoftDeletes; }
要了解关于启用了软删除的模型可以执行的方法,请参阅Laravel文档中的Eloquent Soft Deleting。
数据类型转换
Eloquent 允许您在存储或检索数据之前通过使用转换助手来转换模型属性数据类型。此助手是定义您模型上等效访问器和修改器方法的方便替代方案。
在以下示例中,转换助手将存储在 MongoDB 中的 discovery_dt
模型属性,将其从 MongoDB\\BSON\\UTCDateTime 类型转换为 Laravel 的 datetime
类型。
namespace App\Models; use MongoDB\Laravel\Eloquent\Model; class Planet extends Model { protected $casts = [ 'discovery_dt' => 'datetime', ]; }
提示
Laravel 11 中的数据类型转换
在 Laravel 11 中,您可以通过定义 casts()
方法来指定数据类型转换,而不是使用 $casts
属性。以下代码通过使用 casts()
方法执行与前面的示例相同的转换
protected function casts(): array { return [ 'discovery_dt' => 'datetime', ]; }
要了解更多信息,请参阅 Laravel 文档中的属性转换。
此转换允许您使用 PHP 的 DateTime 类在此字段中处理日期。以下示例展示了使用 Laravel 模型上的转换助手查询三年前发现的行星的 Laravel 查询
Planet::where( 'discovery_dt', '>', new DateTime('-3 years'))->get();
注意
Carbon 日期类
Laravel MongoDB v5.0 版本开始,MongoDB 中的 UTCDateTime
BSON 值在查询结果中作为 Carbon 日期类返回。Laravel 集成在执行此转换时应用默认时区。
要了解更多有关 MongoDB 数据类型的信息,请参阅服务器手册中的BSON 类型。
自定义批量赋值
Eloquent 允许您通过将数据数组传递给 create()
模型方法来创建多个模型及其属性数据。这种插入多个模型的过程称为批量赋值。
批量赋值可以是一种创建多个模型的效率很高的方法。然而,它可能会暴露可利用的安全漏洞。字段中的数据可能包含导致未授权权限或访问的更新。
Eloquent 提供以下特质来保护您的数据免受批量赋值漏洞的侵害
$fillable
包含在批量赋值中可写入的字段$guarded
包含在批量赋值中忽略的字段
重要
我们建议使用 $fillable
代替 $guarded
以防止漏洞。想了解更多关于此建议的信息,请参阅 Laravel 网站上的 安全发布:Laravel 6.18.35, 7.24.0 文章。
以下示例中,模型通过使用 $fillable
属性允许批量赋值字段。
namespace App\Models; use MongoDB\Laravel\Eloquent\Model; class Planet extends Model { protected $fillable = [ 'name', 'gravitational_force', 'diameter', 'moons', ]; }
以下代码示例展示了 Planet
模型的批量赋值。
$planets = [ [ 'name' => 'Earth', 'gravitational_force' => 9.8, 'day_length' => '24 hours' ], [ 'name' => 'Mars', 'gravitational_force' => 3.7, 'day_length' => '25 hours' ], ]; Planet::create($planets);
保存在数据库中的模型只包含 name
和 gravity
字段,因为从 $fillable
属性中省略了 day_length
。
要了解如何更改尝试填充省略在 $fillable
数组中的字段时的行为,请参阅 Laravel 文档中的 批量赋值异常。
扩展第三方模型类
您可以使用Laravel集成来通过在定义模型类时包含DocumentModel
特性来扩展第三方模型类。通过包含此特性,您可以使得第三方类与MongoDB兼容。
当您将DocumentModel
特性应用于模型类时,必须将$keyType
属性设置为'string'
,因为Laravel集成将MongoDB的ObjectId
值转换为类型string
。
扩展类示例
此示例创建了一个Planet
模型类,它扩展了来自名为ThirdPartyPackage
的包中的CelestialBody
类。该Post
类包含DocumentModel
特性,并定义了包括$primaryKey
和$keyType
在内的属性
namespace App\Models; use MongoDB\Laravel\Eloquent\DocumentModel; use ThirdPartyPackage\CelestialBody; class Planet extends CelestialBody { use DocumentModel; protected $fillable = ['name', 'diameter']; protected $keyType = 'string'; }
定义您的类后,您可以像平常一样执行MongoDB操作。
提示
要查看使用DocumentModel
特性的另一个示例,请参阅用户身份验证指南中的Laravel Sanctum部分。
指定修剪行为
Eloquent 允许您指定条件,定期删除不再需要的模型数据。当您安排或运行 model:prune
命令时,Laravel 会调用所有导入 Prunable
和 MassPrunable
特性的模型上的 prunable()
方法,以匹配要删除的模型。
要使用此功能与使用 MongoDB 作为数据库的模型,请将适当的导入添加到您的模型中
MongoDB\Laravel\Eloquent\Prunable
可选地在删除匹配条件的模型之前执行清理步骤MongoDB\Laravel\Eloquent\MassPrunable
不检索模型数据即删除匹配条件的模型
注意
启用大量可修剪模型上的软删除时,必须导入以下 Laravel MongoDB 包
MongoDB\Laravel\Eloquent\SoftDeletes
MongoDB\Laravel\Eloquent\MassPrunable
有关修剪功能的更多信息,请参阅 Laravel 文档中的 修剪模型。
可修剪示例
以下可修剪类包含一个 prunable()
方法,该方法匹配修剪动作删除的模型,以及一个 pruning()
方法,在删除匹配的模型之前运行
namespace App\Models; use MongoDB\Laravel\Eloquent\Model; use MongoDB\Laravel\Eloquent\Prunable; class Planet extends Model { use Prunable; public function prunable() { // matches models in which the solar_system field contains a null value return static::whereNull('solar_system'); } protected function pruning() { // Add cleanup actions, such as logging the Planet 'name' attribute } }
大量可剪枝示例
以下大量可剪枝类包含一个匹配剪枝操作删除的模型的prunable()
方法
namespace App\Models; use MongoDB\Laravel\Eloquent\MassPrunable; use MongoDB\Laravel\Eloquent\Model; class Planet extends Model { use MassPrunable; public function prunable() { // matches models in which the gravitational_force field contains // a value greater than 0.5 return static::where('gravitational_force', '>', 0.5); } }
创建版本化模型模式
您可以通过在Eloquent模型上使用HasSchemaVersion
特质来实现您的应用程序中的模式版本化模式。您可能会选择实现一个模式版本来组织或标准化包含具有不同模式的数据的集合。
提示
有关模式版本化的更多信息,请参阅服务器手册中的模式版本化模型数据教程。
要使用此功能与使用MongoDB作为数据库的模型,将MongoDB\Laravel\Eloquent\HasSchemaVersion
导入添加到您的模型中。然后,将SCHEMA_VERSION
常量设置为1
以设置集合上的第一个模式版本。如果您的集合演变为包含多个模式,您可以在后续模型类中更新SCHEMA_VERSION
常量的值。
在创建模型时,您可以定义migrateSchema()
方法,以在检索模型时指定迁移到当前模式版本。在此方法中,您可以指定对旧模型进行更改以使其与当前模式版本匹配。
当保存没有指定模式版本的模型时,HasSchemaVersion
特质假定它遵循最新的模式版本。当检索不包含schema_version
字段的模型时,特质假定其模式版本为0
并执行迁移。
模式版本化示例
在这个示例场景中,你正在处理一个最初由以下类建模的集合
namespace App\Models; use MongoDB\Laravel\Eloquent\Model; class Planet extends Model { protected $fillable = ['name', 'type']; }
现在,你希望在集合上实现新的模式版本。你可以定义具有以下行为的新模型类
实现
HasSchemaVersion
特性并将当前的SCHEMA_VERSION
设置为2
定义
migrateSchema()
方法以将模式版本小于2
的模型迁移到具有值为'Milky Way'
的galaxy
字段
namespace App\Models; use MongoDB\Laravel\Eloquent\HasSchemaVersion; use MongoDB\Laravel\Eloquent\Model; class Planet extends Model { use HasSchemaVersion; public const SCHEMA_VERSION = 2; protected $fillable = ['name', 'type', 'galaxy']; /** * Migrate documents with a lower schema version to the most current * schema when inserting new data or retrieving from the database. */ public function migrateSchema(int $fromVersion): void { if ($fromVersion < 2) { $this->galaxy = 'Milky Way'; } } }
在以下代码中的 "WASP-39 b"
文档中,schema_version
字段值小于 2
。当你检索文档时,Laravel 集成添加了 galaxy
字段并将模式版本更新为当前版本,2
。
"Saturn"
文档不包含 schema_version
字段,因此在保存时 Laravel 集成将其分配为当前模式版本。
最后,代码从集合中检索模型以展示更改
// Simulates a document in the collection with schema version 1 Planet::insert([ [ 'name' => 'WASP-39 b', 'type' => 'gas', 'schema_version' => 1, ], ]); // Saves a document with no specified schema version $saturn = Planet::create([ 'name' => 'Saturn', 'type' => 'gas', ]); // Retrieves both models from the collection $planets = Planet::where('type', 'gas') ->get();
[ { "_id": ..., "name": "WASP-39 b", "type": "gas", "galaxy": "Milky Way", "schema_version": 2, }, { "_id": ..., "name": "Saturn", "type": "gas", "schema_version": 2, } ]