Laravel - Где хранить статусы (флаги)? Модель, класс или папка конфигурации?

Мне нужно активно использовать статусы в проекте mt. Мне нужны они для моих users (active, suspended и т.д.), Сущности (active, pending_activation, inactive) и для моих подписки (active, on_grace_period, not_subscribed, never_subscribed).

До сих пор я думал, что лучший способ - хранить их в БД, но у меня есть ощущение, что гораздо проще иметь их в других 3 вариантах.

Я также думал, что могу сохранить их в моей модели Eloquent как константы. Например, моя модель подписки будет выглядеть так:

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

и извлечение их, например, в виде лезвия:

// 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

Как сделать то же самое, но с помощью папки config и добавления файла с именем status.php. Доступ к нему в представлении будет выглядеть следующим образом:

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

Есть ли лучший способ?

Кроме того, как насчет другой части уравнения, что означает статус, сохраненный в DB. Должен ли я иметь столбец status для таблицы подписки и хранить то, что приложение диктует или даже делает ставку, создать отдельную таблицу subscription_statuses и иметь foreign_key subscription_status_id в таблице subscriptions?

Ответ 1

Я склонен создавать конкретную модель для статусов, которая действует как перечисление. Поэтому, если у меня есть модель Event, у меня может быть соответствующая модель EventStatus которая выглядит следующим образом:

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

Затем я могу сделать такие проверки:

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

И я обычно добавляю удобные методы к моим моделям:

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

Для "удобных для человека" строк у Ill будет языковой файл с текстовыми строками:

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

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

Ответ 2

Я не согласен с другими ответами. Информация о вашем статусе должна храниться в базе данных. Хорошо спроектированная база данных должна быть ясной и пригодной для использования без приложения. Что произойдет, если вы решите использовать эту базу данных для питания чего-то вроде мобильного приложения? Вы будете извлекать некоторую информацию из базы данных и хранить ее только в Laravel, то есть вам придется дублировать этот список статусов в вашем мобильном приложении и поддерживать ее через два.

Эта информация должна храниться в базе данных.

Вариант 1

Если ваши пользователи могут иметь только один статус, вы должны использовать поле enum со значениями subscribed, subscribed-grace, not-subscribed, never-subscribed

Это так же просто в ваших представлениях:

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

Вариант 2

Если, однако, у вас может быть несколько статусов, то для каждого состояния вы наверняка должны иметь отдельное поле и использовать TINYINT для хранения 1 или 0.

Отдельная таблица состояний?

Я не вижу достаточной причины использовать отдельную таблицу состояния, если вы не ожидаете, что можете добавить еще много статусов, и даже если вы добавляете больше, вы можете просто добавить новые значения в enum или добавить новое поле в зависимости от на какой вариант подойдет.

Таблица состояний будет идеальной, если вы планируете использовать статусы для многих других таблиц в базе данных, кроме пользователей.

Единственной другой причиной отдельной таблицы состояния будет то, что вы решили изменить значение определенного статуса. Это означало бы, что вы могли бы переименовать статус в таблице состояния, но пользователи по-прежнему будут связаны с ним через его первичный ключ. Изменение значения статуса с помощью предыдущих двух методов приведет к изменениям структуры.

Это действительно сводится к тому, как вы ожидаете, что будете использовать их, но нет причин не хранить их в базе данных.

Ответ 3

В моих приложениях я аналогичен @Martin Bean, но я не создаю отдельные классы для статуса, я храню это внутри существующего класса/модели.

Я собираюсь назвать user, subscription и entity объект.

  • У объекта есть status, который существует в нем. Модель и таблица в базе данных.
  • Каждая модель имеет константы возможных значений status, таких как ACTIVE, INACTIVE, PENDING и т.д., и они могут различаться для каждой модели.
  • Создайте методы для работы с ним как 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 a ghost status saved in DB
        return isset($list[$this->status]) 
            ? $list[$this->status] 
            : $this->status;
    }

    /**
     * Some actions will happen only if it 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;
    }
}

Ответ 4

Для каждого метода есть преимущества и недостатки. Хорошо знать каждый.

Таблица. Плюсы и минусы (метод AJReading):

  • Добавление и поддержание таблицы SEEMS утомительно
  • Просто наличие другой таблицы и модели может заставить наш код чувствовать себя более загроможденным (не говоря о том, что это хорошая причина не использовать, просто говоря, что это правда)
  • Это становится неудобно, когда у нас есть логика приложения, зависящая от чего-то в базе данных (вещи в базе данных чувствуют, что они должны быть переменными, когда мы основываем логику приложения на них, они требуются)
  • Теперь у нас есть миграции, но перед ними они были бичем существования разработчиков (они сделали бы переключение между серверами ужасной работой, потому что вам приходилось вспоминать, чтобы добавить новые статусы или ваше приложение сработало бы)... вы бы пришлось делать это с любым изменением базы данных, но все же это были те, которые мне приходилось делать чаще всего
  • Хорошо для целостности данных

Использование констант: за/против (метод Martin Bean):

  • Избегает недостатков выше
  • Они легко ссылаются в вашей логике кода и базы данных на
  • Вам не нужно создавать новую модель или таблицу даже (он делает в своем примере, но вы также можете просто поместить их в модель событий)
  • Они отлично подходят для значений, которые ТОЛЬКО будут использоваться за кулисами.
  • Они уменьшают количество запросов
  • Они просто не любят столько работы. Кажется, что им проще реорганизовать.
  • Con: они становятся неловкими, когда вы их маркируете, извлекаете все из них, получаете описания и т.д. Решение для перевода является хорошим, но если вы не используете переводы в своем приложении, это немного неудобно также.
  • В конечном итоге они нарушают поток ORM, который у вас есть. Если все ваши другие модели расширяют Eloquent, это немного размят форму.
  • Там нет реального соглашения о том, как лучше всего это сделать. Многие люди используют разные методы каждый раз.
  • Как сказал AJReading, если вам нужно использовать только базу данных для другого аспекта проекта, это не сработает.

Я использую метод констант, но иногда я думаю, что мой код может быть более чистым и простым, если бы я использовал таблицы. Это жесткий вызов. Я бы хотел, чтобы там было хорошо документированное решение для постоянного метода, чтобы хотя бы создать согласованность, но я еще не видел его. В любом случае я не думаю, что есть правильный или неправильный ответ. Выберите один и идите с ним!

Ответ 5

Для решений такого характера спросите себя:

"Будет ли когда-нибудь экземпляр моего приложения, где он будет смысл для этих констант иметь разные значения?"

например. тестовая среда, какой-то клон, некоторые еще не определены, но возможны будущие версии...

Если ответ на этот вопрос "да", то он должен, вероятно, перейти в конфигурацию приложения.

Если маловероятно (или глупо) изменить значения, они принадлежат и должны идти в модели.

Я предлагаю, чтобы в этом случае не было разумной причины когда-либо иметь версию приложения с разными значениями, поэтому я бы поместил ее в модель.

Ответ 6

Если мы определим константы и массивы их свойств в модели, то это приведет к ее росту. Я использую отдельный класс для констант. Я также создал класс, который помогает контролировать свойства констант. Я недавно отправил это на github.