web-dev-qa-db-fra.com

Où mettre / comment gérer les enums à Laravel?

Laravel a a <select> assistant de formulaire qui prend en entrée un dictionnaire. J'aime garder les valeurs de tout cela dans un endroit central. Par exemple, je pourrais avoir une énumération qui ressemble à ceci:

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

Ce que je veux utiliser à la fois dans ma vue/modèle et dans la base de données:

Schema::create('customers', function (Blueprint $table) {
    $table->increments('id');
    $table->enum('pri_phone_type',array_keys($phoneTypes));
    ...
});
  1. Y at-il un endroit recommandé pour mettre ceux-ci?
  2. Puis-je les rendre globaux pour pouvoir y accéder facilement dans toutes mes vues?
47
mpen

Vous avez plusieurs options pour gérer les enums. Avant d’en examiner quelques-uns, j’encourage fortement et non à utiliser le type de colonne DB enum.

Les énumérations de base de données sont problématiques pour un certain nombre de raisons. Je suggère de lire cet article par exemple:

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

Donc, avec cela, examinons quelques autres options.

Utilisation de Laravel config

Puisque vous utilisez Laravel, une option très simple consiste à coller un tableau d’options dans un fichier de configuration.

Supposons que vous créez un nouveau fichier config/enums.php Avec les éléments suivants:

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

Vous pouvez maintenant accéder à config('enums.phone_types') n'importe où dans votre code, y compris votre modèle de lame.

Utiliser un paquet PHP

La réponse de @Banford montre comment effectuer un comportement de base de type enum avec des constantes de classe. Si vous aimez cette approche, je vous recommande de consulter cet article et ce package qui s’appuient sur ce concept pour fournir des enums de type fortement:

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

https://github.com/spatie/enum

Vous créeriez une classe comme celle-ci:

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

Et maintenant, vous pouvez appeler PhoneTypes::home() dans votre application. Consultez la documentation de ce paquet pour savoir comment créer une carte de valeurs, si vous le souhaitez.

Utilisation des relations de base de données

Si vous teniez vraiment à gérer vos options dans la base de données, je créerais une table de base de données distincte phone_types Et créerait une relation avec votre customers table. C'est toujours une bien meilleure option que d'utiliser le type de colonne enum.

54
jszobody

Je ne suis pas d'accord avec la réponse acceptée ici. Je pense que les enums peuvent être très utiles pour ce genre de chose. Je préfère traiter les enum en tant que types et implémenter les méthodes dont vous avez besoin sur la classe de base Enum pour vous fournir les fonctionnalités dont vous avez besoin, telles que l'obtention d'un dictionnaire.

Mon exemple simple ci-dessous:

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());
    }
}

Exemple d'utilisation:

PhoneType::getKeys();

Voir PHP et Enumerations pour plus de détails et un exemple plus détaillé.

57
Banford

En s'appuyant sur la réponse de @Banfords, les constantes PHP7 peuvent désormais être des tableaux:

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

...
11
Kirill Fuchs

En plus de la réponse de @ Banford:

J'ai récemment mis sur pied un paquet qui rend le travail avec des enums in Laravel beaucoup plus agréable. C'est une combinaison de différentes implémentations que j'avais trouvées en cherchant comment faire la même chose ici).

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

Dans ce cas, vous pouvez faire quelque chose comme ceci:

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

Les valeurs sont alors accessibles via:

PhoneTypes::Work // 1

Je recommanderais de toujours définir les valeurs sur des entiers et de les stocker ensuite dans la base de données en tant que ints.

La classe de base Enum contient des méthodes permettant d’obtenir toutes les clés et toutes les valeurs sous forme de tableaux. Le package présente également quelques autres avantages qui peuvent être utiles dans ce cas, tels que la validation - de sorte qu'un utilisateur ne puisse pas ajouter de valeur inexistante à la base de données.

Il y a aussi un générateur qui est très pratique.

J'espère que cela est utile pour quelqu'un.

7
BenSampo

Je viens d'avoir un problème similaire, pour moi Accesseurs et mutateurs Eloquent a fonctionné le mieux. Pour cette question, cela ressemblerait à:

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);
    }
}

Veuillez noter que dans la base de données, vous devez enregistrer les valeurs numériques, où 0 correspond à une cellule, 1 à la maison et 2 au travail. Deuxièmement, il serait sage d’utiliser les traductions ici plutôt que propriété protégée.

4
lchachurski

Vous ne devriez pas utiliser du tout enum.

Le fonctionnaire Laravel 5.1 documentation déclare:

Remarque: le fait de renommer des colonnes dans une table avec une colonne enum n'est actuellement pas pris en charge.

Cela se produit lorsque vous avez une colonne enum dans votre table de base de données. Que vous essayiez de rename une autre colonne ou que vous changiez une autre colonne en nullable, le bogue apparaîtra. C'est un problème avec Doctrine\DBAL.

Type de base de données inconnu énuméré demandé

Même avec laravel 5.8), le problème n’est pas résolu.

Je dois ajouter que vous aurez le même problème lorsque ajout des options disponibles dans la déclaration de la colonne enum.

Cela me conduit à la conclusion que Vous devez utiliser enum avec précaution. ou même Vous ne devez pas utiliser enum du tout.

Voici un exemple de la difficulté avec laquelle ajouter les options disponibles dans la déclaration de colonne enum

dites que vous avez ceci:

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

et vous devez rendre plus de types disponibles

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']);
    });
}
2
Yevgeniy Afanasyev