如何在Laravel中设置你的数据模型

63 阅读4分钟

数据模型是任何Laravel应用程序中最重要的部分之一。许多系统都是围绕这个数据模型设计的, 所以它通常是我们在开发过程中最先接触的东西之一.我们中的一些人已经做了很多年,对如何处理这个问题有一个很好的想法 - 而其他人可能还不习惯。在我知道有框架这种东西之前,我就学会了数据建模,用CREATE TABLE 语句设计我的数据模型。

在本教程中, 我将介绍如何在你的Laravel应用程序中进行数据建模 - 以及一些我认为有用的提示.

本教程是一个正在进行的系列教程的第一部分, 在这个系列中, 我们应该从头到尾一起建立一个完整的可生产的系统.换句话说, 从IDE到服务器.

我们要建立什么?我很高兴你这么问。我可以在这里做一些简单的事情,比如一个ToDo应用程序或一个博客--但你不会从中学到任何有用的东西。相反,我们将建立一些独特的、令人兴奋的、有许多活动部件的东西,到最后,这应该是一些有价值的东西。最近我去寻找一个会议室预订系统,说实话,我很难找到一个。所以我们将在Laravel中建立一个开源的系统。这里的目的是以我们在生产环境中期望的方式建立一些东西,同时提供一些免费的东西。

这个会议室管理平台将包括什么?这不会是一个SaaS风格的应用程序,任何人都可以注册并使用它,这将是你自己下载并运行的东西。在这个阶段,考虑这些决定是很关键的,因为它为我们的数据模型提供了很多信息。

我们希望我们的应用程序的工作方式是,一开始,一个配置过程会发生,重要的设置指示可以通过。一个整体的系统管理员可以被邀请到平台上,让他们邀请用户并按要求设置系统。

让我们先来看看我们的用户模型,它和典型的Laravel用户模型不太一样。最终, 我们将重构我们的用户模型到一个为我们控制认证的包 - 但现在, 我们将保持简单。

我们的用户模型将需要一个额外的列,叫做type,这将是一个Enum。我们将保留电子邮件验证列,以便在基于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模型的改动很小,只是增加了一个可填充的列,并确保我们可以将类型属性投给我们的Enum。

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本身和它的可用选项。

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应用时,都会按照这个顺序重复的一个过程。它给了我一个抽象的模型来传递,而不是一个简单的数组,同时强迫属性的类型安全水平。有时我需要直接访问这些属性, 但不是很频繁, 当我需要时, 我会创建一个访问器, 而不是改变属性的可见性.