在 Laravel 中设置您的数据模型
发表于 作者 Steve McDougall
数据模型是任何 Laravel 应用程序最重要的部分之一。许多系统将围绕此数据模型设计,因此它通常是我们开发过程中的首要任务之一。我们中的一些人已经做了很多年,对如何处理它有一个很好的了解 - 而另一些人可能还没有习惯它。在我了解到有像框架这样的东西之前,我就学习了数据建模,在 CREATE TABLE
语句中设计我的数据模型。
在本教程中,我将逐步介绍如何在 Laravel 应用程序中处理数据建模 - 以及一些我认为有用的技巧。
本教程是一个持续系列的第一部分,到最后,我们将一起从头到尾构建一个完整的可投入生产的系统。换句话说,从 IDE 到服务器。
我们要构建什么?我很高兴你问。我可以在这里做一些简单的事情,比如一个待办事项应用程序或一个博客 - 但你不会从中学到任何有用的东西。相反,我们将构建一些独特而令人兴奋的东西,它有相当多的活动部件,到最后,应该会成为一些有价值的东西。最近我在寻找一个会议室预订系统,老实说,我很难找到一个。所以我们将在 Laravel 中构建一个开源的。这里的目的是以我们预期在生产环境中使用的方式构建一些东西,同时提供免费的东西。
这个会议室管理平台中将包含什么?这不会是一个 SaaS 风格的应用程序,任何人都可以注册并使用它,这将是您可以下载并自己运行的东西。在这个阶段思考这些决定至关重要,因为它会影响我们的大部分数据模型。
我们希望我们的应用程序的工作方式是,首先,会进行一个配置过程,其中可以完成重要的设置说明。可以邀请一个系统管理员进入平台,以允许他们邀请用户并根据需要设置系统。
让我们首先看看我们的用户模型,它与典型的 Laravel 用户模型略有不同。最终,我们将重构我们的用户模型到一个包中,该包为我们控制身份验证 - 但现在,我们将保持简单。
我们的用户模型将需要一个名为类型的附加列,它将是一个枚举。我们将保留电子邮件验证列,以便在基于 API 的环境中更有效地验证用户。
现在用户迁移应该如下所示
public function up(): void{ Schema::create('users', function (Blueprint $table): void { $table->id(); $table->string('name'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->string('type')->default(Type::ADMIN->value); $table->timestamps(); });}
如您所见,除了我们想要添加的附加列之外,它对于 Laravel 应用程序来说是相对标准的。从这里,我们可以开始查看我们需要为用户创建的模型工厂。
final class UserFactory extends Factory{ protected $model = User::class; public function definition(): array { return [ 'name' => $this->faker->name(), 'email' => $this->faker->unique()->safeEmail(), 'email_verified_at' => now(), 'password' => Hash::make( value: 'password', ), 'type' => Type::ADMIN, ]; } public function unverified(): UserFactory { return $this->state( state: fn (array $attributes) => ['email_verified_at' => null], ); } public function type(Type $type): UserFactory { return $this->state( state: fn (array $attributes) => ['type' => $type], ); }}
我们添加了想要应用于任何创建的用户的一个默认类型。但是,我们还创建了一个辅助方法,以便我们可以自定义想要创建的用户类型。
这将我们带到模型以及我们想要对其应用的更改。除了一个额外的可填充列和确保我们可以将类型属性转换为我们的枚举之外,Eloquent 模型的更改很少。
final class User extends Authenticatable implements MustVerifyEmail{ use HasApiTokens; use HasFactory; use Notifiable; protected $fillable = [ 'name', 'email', 'password', 'type', ]; protected $hidden = [ 'password', ]; protected $casts = [ 'type' => Type::class, 'email_verified_at' => 'datetime', ];}
在我们详细介绍之前,您可能想知道枚举本身及其可用选项。
enum Type: string{ case ADMIN = 'admin'; case OFFICE_MANAGER = 'office manager'; case STAFF = 'staff';}
我们的应用程序将由以下组成
- 管理员;负责配置系统和管理系统的人员。
- 办公室经理;有权覆盖系统上的预订的人员。
- 员工;有权预订会议室的系统用户。
此工作流程是管理员将邀请办公室经理,然后办公室经理可以开始将员工成员加入平台。
除了对数据的数据库表示进行建模之外,我们还需要一种方法来了解应用程序中的数据。我们可以通过使用域传输对象(简称 DTO)来实现这一点。
我们首先遍历此数据模型的数据库内容,然后找出应用程序中需要什么。但是,我们有时也需要在这些对象存在于数据库中之前创建这些对象。
final class User implements DataObjectContract{ public function __construct( private readonly string $name, private readonly string $email, private readonly Type $type, ) {} public function toArray(): array { return [ 'name' => $this->name, 'email' => $this->email, 'type' => $this->type, ]; }}
为了创建或邀请潜在用户或了解有关用户的任何信息,我们需要访问他们的姓名、电子邮件和类型。这涵盖了大多数用例,因为资源主要通过路由模型绑定来识别。
现在,我们有了通过数据库和应用程序了解数据的方法。这是我在构建任何 Laravel 应用程序时按顺序重复的过程。它为我提供了从模型到传递的抽象,而无需它成为一个简单的数组,同时在属性上强制执行类型安全级别。有时我需要直接访问属性,但并不经常,当我这样做时,我会创建一个访问器而不是更改属性的可见性。