在Laravel中放置/如何处理枚举?

时间:2014-09-07 00:00:22

标签: php laravel enums

Laravel有a <select> form helper,它将词典作为输入。我喜欢把所有这些的价值保持在一个中心位置。例如,我可能有一个看起来像这样的枚举:

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

我想在我的视图/模板和数据库中使用它:

Schema::create('customers', function (Blueprint $table) {
    $table->increments('id');
    $table->enum('pri_phone_type',array_keys($phoneTypes));
    ...
});
  1. 有推荐的地方放这些吗?
  2. 我可以将它们设为全局,以便我可以在所有视图中轻松访问它们吗?

7 个答案:

答案 0 :(得分:56)

我不同意这里接受的答案。我觉得枚举对于这种事情非常有用。我更喜欢将枚举视为类型,并在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 and Enumerations

答案 1 :(得分:49)

您有多种处理枚举的选项。在我们看一些之前,我首先强烈建议您使用数据库enum列类型。

由于多种原因,数据库枚举存在问题。我建议阅读这篇文章,例如:

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的答案显示了如何使用类常量执行基本的枚举类型行为。如果您喜欢这种方法,我建议您查看本文和基于此概念构建的包,以提供强类型枚举:

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数据库表并与您的customers表创建关系。这仍然比使用enum列类型更好的选择。

答案 2 :(得分:10)

基于@Banfords答案,PHP7常量现在可以是数组:

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

...

答案 3 :(得分:7)

除了@ 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

我建议始终将值设置为整数,然后将它们作为整数存储在数据库中。

基本枚举类具有将所有键和值作为数组获取的方法。该软件包还具有一些其他好处,在这种情况下可能很有用,例如验证 - 这样用户就无法向DB添加不存在的值。

还有一个非常方便的发电机。

我希望这对某人有用。

答案 4 :(得分:4)

刚才有类似问题,对我来说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是工作。其次,在这里使用翻译而不是保护财产是明智的。

答案 5 :(得分:1)

您完全不应使用枚举。

Laravel 5.1 documentation官方声明:

  

注意:当前不支持使用enum列重命名表中的列。

当数据库表中有一个enum列时,就会发生这种情况。不管您是尝试rename 另一个列,还是将另一个列更改为nullable,都会出现该错误。这是Doctrine \ DBAL的问题。

  

请求的未知数据库类型枚举

即使使用laravel 5.8,问题也无法解决。

我需要补充的是,当将可用选项添加到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']);
    });
}

答案 6 :(得分:0)

假设您需要一个下拉选项

试试这个:

namespace App;

use Illuminate\Database\Eloquent\Model;

class Customer extends Model
{
    const PHONE_TYPES = [
        [
            'label' => 'Cellular',
            'value' => 'Cellular',
        ],
        [
            'label' => 'Home',
            'value' => 'Home',
        ],
        [
            'label' => 'Work',
            'value' => 'Work',
        ],
    ];


    public function getPhoneTypesLabelAttribute()
    {
        return collect(static::PHONE_TYPES)->firstWhere('value', $this->phone_types)['label'] ?? '';
    }
}

在您的控制器中,假设在 create 方法下执行以下操作:

public function create(Customer $customer)
{
    return response([
        'meta' => [
            'customer'   => Customer::get(['id', 'first_name']),
            'phone_types' => Customer::PHONE_TYPES,
        ],
    ]);
}

然后,在您的刀片模板中

dd($phone_types);