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

mpe*_*pen 50 php enums laravel

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

$phoneTypes = [
    'CELL' => "Cellular",
    'HOME' => "Home",
    'WORK' => "Work",
];
Run Code Online (Sandbox Code Playgroud)

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

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

Ban*_*ord 58

我不同意这里接受的答案.我觉得枚举对于这种事情非常有用.我更喜欢将枚举视为类型,并在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());
    }
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

PhoneType::getKeys();
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息和更深入的示例,请参阅PHP和枚举.

  • 将枚举更改为tinyint可能仍然会更好,然后只需将每个常量映射到整数!这样你就可以随时添加第四部手机(很可能会发生).ALTER表命令很昂贵,不值得冒险.此外,像doctrine这样的一些框架甚至不支持Enum进行模式创建. (3认同)
  • 枚举的一个很好的用例是性别。您通常只会与男性,女性或未指定对象打交道。多余的表没有意义,因为这三个值涵盖了所有可能的情况。当然,在某些项目中可能会有用例来指定更多性别,但这是例外。 (2认同)

jsz*_*ody 56

您有几种处理枚举的选项.在我们看一些之前,我首先强烈建议您不要使用DB 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",
    ]
];
Run Code Online (Sandbox Code Playgroud)

您现在可以访问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
{
}
Run Code Online (Sandbox Code Playgroud)

现在你可以PhoneTypes::home()在你的应用程序中调用.查看该软件包的文档,了解如何创建值映射(如果需要).

使用数据库关系

如果您真的想要管理数据库中的选项,我将创建一个单独的phone_types数据库表并与您的customers表创建关系.这仍然是比使用enum列类型更好的选择.

  • 为什么你更喜欢为很少变化的十几个非常小的列表中的每一个创建单独的表? (10认同)
  • 除其他事项外,我可以查询备有手机的客户吗?当我确信某些事情不会改变的时候,它会改变。我希望事先进行设计,以便亲自进行更改很简单。 (2认同)
  • 我应该澄清一下:有些时候我有一个`varchar`列类型,其中包含一些我的app控制的可能值.但是,如果我希望数据库调节可能的值,我使用关系表.我非常不喜欢在数据库级别使用`enum`,这里有一篇文章为什么:http://komlenic.com/244/8-reasons-why-mysqls-enum-data-type-is-evil/ (2认同)

Kir*_*chs 13

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

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

...
Run Code Online (Sandbox Code Playgroud)

  • 您能解释一下为什么不应该将它们用作查找表吗? (7认同)

小智 7

除了@ Banford的回答:

我最近整理了一个包,使得在Laravel中使用枚举更好.这是我在研究如何做同样事情时发现的各种实现的组合(因此我在这里).

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

在这种情况下,您可以执行以下操作:

final class PhoneTypes extends Enum
{
    const Cellular = 0;
    const Work = 1;
    const Home = 2;
}
Run Code Online (Sandbox Code Playgroud)

然后可以使用以下方法访问这些值:

PhoneTypes::Work // 1
Run Code Online (Sandbox Code Playgroud)

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

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

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

我希望这对某人有用.


Yev*_*yev 7

你根本不应该使用枚举。

Laravel 5.1 官方文档指出:

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

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

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

即使使用 laravel 5.8,问题也没有解决。

我需要补充一点,在将可用选项添加enum列声明中时,您会遇到同样的问题。

它使我得出一个结论,您应该谨慎使用 enum。甚至你根本不应该使用枚举。

这是将可用选项添加enum列声明中的难度示例

说你有这个:

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

并且您需要提供更多类型

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']);
    });
}
Run Code Online (Sandbox Code Playgroud)


lch*_*ski 5

刚刚遇到过类似的问题,对我而言,雄辩的访问者和变异者表现最好。对于这个问题,它将是这样的:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,您应该在数据库中保存数值,其中0是单元格,1是家庭,2是工作。其次,明智的做法是在此处使用翻译而不是受保护的财产。