Laravel - 在哪里存储状态(标志)?模型,Class 还是配置文件夹?

Laravel - Where to store statuses (flags)? Model, Class or config folder?

我需要在 mt 项目中广泛使用状态。我的 usersactivesuspended 等)、一个实体(activepending_activationinactive)和我的订阅(activeon_grace_periodnot_subscribednever_subscribed)。

到目前为止,我认为最好的方法是将它们存储在数据库中,但我感觉将它们放在其他 3 个选项中要容易得多。

我还认为我可以将它们作为常量存储在我的 Eloquent 模型中。例如,我的订阅模型如下所示:

// SubscriptionModel
const SUBSCRIBED_ACTIVE = 1;
const SUBSCRIBED_ON_GRACE_PERIOD = 2;
const NOT_SUBSCRIBED = 3;
const NEVER_SUBSCRIBED = 4;

并检索它们,例如在 blade 视图中:

// subscription/index.blade.php
@if($user->subscription->status == /App/SubscriptionModel::SUBSCRIBED_ACTIVE)
    <div>You are subscribed. Thank you</div>
@elseif($user->subscription->status == /App/SubscriptionModel::NEVER_SUBSCRIBED)
    <div>You need to create a subscription before being granted full access!</div>
@elseif(...)
    // and so on

如何做同样的事情,但使用配置文件夹并添加一个名为 status.php 的文件。在视图中访问它就像:

@if($user->subscription->status == Config::get('status.subscription.SUBSCRIBED_ACTIVE'))
<div>You are subscribed. Thank you</div>
@elseif(...)
// etc

有没有更好的方法?

此外,等式的另一部分如何,即存储在 DB 中的状态。我是否应该只有一个 status 列用于订阅 table 并存储应用程序指示的内容,或者甚至更好地创建一个单独的 table subscription_statuses 并有一个 foreign_key subscription_status_idsubscriptions table?

对于这种性质的决定,问问自己:

"Will there ever be an instance of my application where it would make sense for these constants to have different values?"

例如一个测试环境,某种克隆,一些尚未定义但可能是未来版本...

如果该问题的答案是 "yes",那么它可能应该进入应用程序配置。

如果值不太可能(或愚蠢)发生变化,它们属于并且应该进入模型。

我建议在这种情况下,没有合理的理由让应用程序版本具有不同的值,因此我将其放入模型中。

我不同意其他答案。您的状态信息应该存储在数据库中。设计良好的数据库应该在没有应用程序的情况下清晰易用。如果您决定也使用此数据库来支持移动应用程序之类的东西,会发生什么情况?您将从数据库中取出一些信息并将其仅存储在 Laravel 中,这意味着您也必须在您的移动应用程序中复制该状态列表,并在两者之间维护它。

这种信息应该存储在数据库中。

选项 1

如果您的用户只能有一个状态,那么您应该使用一个 enum 字段,其值为 subscribedsubscribed-gracenot-subscribednever-subscribed

这在您看来很简单:

@if($user->subscription->status == 'subscribed'

选项 2

但是,如果您可能有多个状态,那么几乎可以肯定每个状态都有一个单独的字段,并使用 TINYINT 来存储 10

独立状态table?

我看不出使用单独状态 table 的充分理由,除非您预计可能会添加更多状态,即使您要添加更多状态,也可以向 [=11 添加新值=] 或根据适合的选项添加新字段。

如果您计划将状态用于数据库中除用户之外的许多其他 table,那么状态 table 将是理想的选择。

单独状态 table 的唯一其他原因是您决定更改特定状态的含义。这意味着您可以重命名状态 table 中的状态,但用户仍会通过它的主键链接到它。使用前两种方法改变状态的含义会涉及到结构的改变。

这实际上取决于您预期如何使用它们,但没有理由不将它们保存在数据库中。

我倾向于为状态创建一个特定的模型,作为一个枚举。因此,如果我有一个 Event 模型,我可能会有一个相应的 EventStatus 模型,如下所示:

class EventStatus
{
    public const CANCELLED = 'EventCancelled';
    public const POSTPONED = 'EventPostponed';
    public const RESCHEDULED = 'EventRescheduled';
    public const SCHEDULED = 'EventScheduled';
}

然后我可以像这样检查:

$event->status === EventStatus::CANCELLED;

而且我通常也会为我的模型添加便捷方法:

class Event extends Model
{
    public function isCancelled(): bool
    {
        return $this->status === EventStatus::CANCELLED;
    }
}

对于“人性化”的字符串,我会有一个包含文本字符串的语言文件:

<?php // resources/lang/en/event_status.php

return [
    EventStatus::CANCELLED => 'Cancelled',
    EventStatus::POSTPONED => 'Postponed',
    EventStatus::RESCHEDULED => 'Rescheduled',
    EventStatus::SCHEDULED => 'Scheduled',
];

每种方法各有利弊。了解每一个都很好。

Table - 优点和缺点(AJReading 的方法):

  • 添加和维护 table SEEMS 很乏味
  • 只是有另一个 table 和模型可以让我们的代码感觉更混乱(并不是说这是不使用的一个很好的理由只是说它有点真实)
  • 当我们的应用程序逻辑依赖于数据库中的某些东西时会变得很尴尬(数据库中的东西感觉它们应该是可变的,当我们将应用程序逻辑基于它们时它们是必需的)
  • 现在我们有迁移,但在它们之前,这些曾经是开发人员存在的祸根(它们会使服务器之间的切换成为一件可怕的苦差事,因为你必须记住添加新状态,否则你的应用程序会崩溃)......您将不得不对任何数据库更改执行此操作,但这些仍然是我最常执行的操作
  • 有利于数据完整性

使用常量:Pros/cons(Martin Bean 的方法):

  • 避免上述缺点
  • 这些很容易在您的代码和基础逻辑中引用
  • 您甚至不必创建新模型或 table(他在他的示例中这样做,但您也可以将它们放在事件模型中)
  • 它们非常适合仅在幕后使用的值
  • 他们减少了查询量
  • 他们就是不喜欢那么多工作。它们似乎更容易重构。
  • 缺点:当您标记它们、检索所有它们、获取描述等时,它们会变得有点尴尬。翻译解决方案是一个很好的解决方案,但如果您不在您的应用程序中使用翻译,那么这是一个也有点尴尬。
  • 最终他们会破坏您正在进行的 ORM 流程。如果您所有其他模型都扩展 Eloquent 那么这会稍微打破常规。
  • 对于如何最好地做到这一点还没有达成真正的共识。很多人每次都使用不同的方法。
  • 就像 AJReading 所说的,如果您需要单独使用数据库来处理项目的另一个方面,那将行不通

我使用常量方法,但有时我认为如果我使用 tables,我的代码可能会更清晰、更简单。这是一个艰难的决定。我希望常量方法有一个有据可查的解决方案,至少可以创建一致性,但我还没有看到。无论哪种方式,我认为没有正确或错误的答案。挑一个一起去吧!

在我的应用程序中,我与@Martin Bean 类似,除了我不为状态创建单独的 类,我将其存储在现有的 class/Model.

我要将 usersubscriptionentity 称为 实体

  • 实体 有一个存在于它的模型中的 status 和存在于数据库中的 table。
  • 每个模型都有 status 可能值的常量,例如 ACTIVEINACTIVEPENDING 等,每个模型的值可能会有所不同。
  • 创建处理方法,如 getStatusLabel()listStatus()isActive()isX()
  • 那些 isActive/X() 仅在确实需要时才创建,也许一个模型有 4 个状态,但您只对一个特定的进行比较,所以我只为该状态创建一个 isX()

例子

class User
{
    const STATUS_ACTIVE    = 1;
    const STATUS_SUSPENDED = 2;
    const STATUS_INACTIVE  = 3;

    /**
     * Return list of status codes and labels

     * @return array
     */
    public static function listStatus()
    {
        return [
            self::STATUS_ACTIVE    => 'Active',
            self::STATUS_SUSPENDED => 'Suspended',
            self::STATUS_INACTIVE  => 'Inactive'
        ]
    }

    /**
     * Returns label of actual status

     * @param string
     */
    public function statusLabel()
    {
        $list = self::listStatus();

        // little validation here just in case someone mess things
        // up and there's a ghost status saved in DB
        return isset($list[$this->status]) 
            ? $list[$this->status] 
            : $this->status;
    }

    /**
     * Some actions will happen only if it's active, so I have 
     * this method for making things easier.
     * Other status doesn't have a specific method because
     * I usually don't compare agains them
     * @return Boolean
     */
    public function isActive()
    {
        return $this->status == self::STATUS_ACTIVE;
    }
}