Подтвердить что ты не робот

Где поставить/как обрабатывать перечисления в Laravel?

Laravel имеет a <select> хелпер формы, который принимает в качестве входного словаря словарь. Мне нравится сохранять ценности для всех из них в центральном месте. Например, у меня может быть перечисление, которое выглядит так:

$phoneTypes = [
    'CELL' => "Cellular",
    'HOME' => "Home",
    'WORK' => "Work",
];

Что я хочу использовать как в моем представлении/шаблоне, так и в базе данных:

Schema::create('customers', function (Blueprint $table) {
    $table->increments('id');
    $table->enum('pri_phone_type',array_keys($phoneTypes));
    ...
});
  • Есть ли рекомендуемое место для их размещения?
  • Могу ли я сделать их глобальными, чтобы я мог легко получить доступ к ним во всех своих представлениях?
4b9b3361

Ответ 1

У вас есть несколько вариантов обработки перечислений. Прежде чем мы рассмотрим некоторые из них, я бы настоятельно рекомендовал вам не использовать тип столбца enum DB.

Перечень баз данных проблематичен по ряду причин. Я предлагаю прочитать эту статью, например:

http://komlenic.com/244/8-reasons-why-mysqls-enum-data-type-is-evil/

Итак, давайте рассмотрим несколько других вариантов.

Использование конфигурации Laravel

Поскольку вы используете Laravel, один очень простой вариант - вставить массив параметров в файл конфигурации.

Допустим, вы создали новый файл config/enums.php со следующим:

return [
    'phone_types' => [
        'CELL' => "Cellular",
        'HOME' => "Home",
        'WORK' => "Work",
    ]
];

Теперь вы можете получить доступ к config('enums.phone_types') любом месте вашего кода, включая ваш шаблон Blade.

Использование пакета PHP

Ответ @Banford показывает, как сделать базовое поведение типа enum с константами класса. Если вам нравится такой подход, я рекомендую посмотреть эту статью и пакет, основанный на этой концепции, чтобы обеспечить строго перечисления типов:

https://stitcher.io/blog/php-enums

https://github.com/spatie/enum

Вы бы создали такой класс:

/**
 * @method static self cell()
 * @method static self home()
 * @method static self work()
 */
class PhoneTypes extends Enum
{
}

И теперь вы можете вызвать PhoneTypes::home() в вашем приложении. Посмотрите документацию для этого пакета, чтобы увидеть, как вы можете создать карту значений, если хотите.

Использование связей БД

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

Ответ 2

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

Мой простой пример ниже:

abstract class PhoneType extends Enum {
    const Cell = "Cellular";
    const Home = "Home";
    const Work = "Work";
}

abstract class Enum {
    static function getKeys(){
        $class = new ReflectionClass(get_called_class());
        return array_keys($class->getConstants());
    }
}

Пример использования:

PhoneType::getKeys();

Подробнее см. PHP и перечисления и более подробный пример.

Ответ 3

Основываясь на ответе @Banfords, теперь с константами PHP7 могут быть массивы:

class User extends Authenticatable
{
    /**
     * The possible genders a user can be.
     */
    const GENDER = [
        'Male',
        'Female',
        'Unspecified'
    ];

...

Ответ 4

В дополнение к ответу @Banford:

Недавно я собрал пакет, который делает работу с перечислениями в Laravel намного приятнее. Это комбинация различных реализаций, которые я обнаружил при исследовании того, как сделать то же самое (и поэтому я здесь).

https://github.com/BenSampo/laravel-enum

В этом случае вы можете сделать что-то вроде следующего:

final class PhoneTypes extends Enum
{
    const Cellular = 0;
    const Work = 1;
    const Home = 2;
}

Значения могут быть доступны с помощью:

PhoneTypes::Work // 1

Я бы рекомендовал всегда устанавливать значения в целые числа и впоследствии сохранять их в БД в виде целых чисел.

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

Там также генератор, который очень удобно.

Я надеюсь, что это пригодится кому-то.

Ответ 5

Просто у меня была аналогичная проблема, для меня Eloquent Accessors and mutators работали лучше всего. Для этого вопроса это будет выглядеть так:

namespace App;

use Illuminate\Database\Eloquent\Model;

class Customer extends Model
{
    /**
    * @var array
    */
    protected $phoneTypes = [
        'Cellular',
        'Home',
        'Work'
    ];

   /**
    * @param int $value
    * @return string|null
    */
    public function getPhoneTypeAttribute($value)
    {
        return Arr::get($this->phoneTypes, $value);
    }
}

Обратите внимание, что в базе данных вы должны сохранять числовые значения, где 0 - ячейка, 1 - домашняя и 2 - работа. Во-вторых, было бы разумно использовать переводы здесь вместо защищенного свойства.

Ответ 6

Вы не должны использовать enum вообще.

Официальная документация Laravel 5.1 гласит:

Примечание. Переименование столбцов в таблице со столбцом перечисления в настоящее время не поддерживается.

Это происходит, когда в вашей таблице базы данных есть столбец enum. Если вы пытаетесь rename другой столбец или изменить другой столбец на nullable, появится ошибка. Это проблема с Doctrine\DBAL.

Запрошено неизвестное перечисление типа базы данных

Даже с laravel 5.8 проблема не решена.

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

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

Вот пример того, насколько сложно будет добавить доступные опции в объявление столбца enum

скажем, у вас есть это:

Schema::create('blogs', function (Blueprint $table) {
    $table->enum('type', [BlogType::KEY_PAYMENTS]);
    $table->index(['type', 'created_at']);
...

и вам нужно сделать больше типов доступными

public function up(): void
{
    Schema::table('blogs', function (Blueprint $table) {
        $table->dropIndex(['type', 'created_at']);
        $table->enum('type_tmp', [
            BlogType::KEY_PAYMENTS,
            BlogType::KEY_CATS,
            BlogType::KEY_DOGS,
        ])->after('type');
    });

    DB::statement('update 'blogs' as te set te.'type_tmp' = te.'type' ');

    Schema::table('blogs', function (Blueprint $table) {
        $table->dropColumn('type');
    });

    Schema::table('blogs', function (Blueprint $table) {
        $table->enum('type', [
            BlogType::KEY_PAYMENTS,
            BlogType::KEY_CATS,
            BlogType::KEY_DOGS,
        ])->after('type_tmp');
    });

    DB::statement('update 'blogs' as te set te.'type' = te.'type_tmp' ');

    Schema::table('blogs', function (Blueprint $table) {
        $table->dropColumn('type_tmp');
        $table->index(['type', 'created_at']);
    });
}