O uso desta biblioteca não é mais recomendado, principalmente para novos projetos. PHP 8.1 suporta enums nativamente.
Consulte #332.
Implementação de enumeração simples, extensível e poderosa para Laravel.
Pares de valores-chave Enum como constantes de classe
Conjunto completo de métodos
Instanciação de enum
Enumerações sinalizadas/bit a bit
Dica de tipo
Elenco de atributos
Gerador de artesão Enum
Regras de validação para passar chaves ou valores enum como parâmetros de entrada
Suporte de localização
Extensível via Macros
Criado por Ben Sampson
Guia
Instalação
Migrar para enums PHP nativos
Biblioteca Enum
Uso Básico
Definição de Enum
Instanciação
Propriedades da instância
Transmissão de instância
Igualdade de instância
Dica de tipo
Enum sinalizado/bit a bit
Elenco de atributos
Migrações
Validação
Localização
Personalizando descrições
Personalizando a descrição da classe
Personalizando descrições de valores
Estendendo a classe base Enum
Integração Laravel Nova
Integração PHPStan
Lista de Comandos Artesãos
Referência de classe Enum
Esboços
Você está lendo a documentação do 6.x
Se você estiver usando o Laravel 8, consulte a documentação do 4.x
Se você estiver usando o Laravel 7, consulte a documentação do 2.x
Se você estiver usando o Laravel 6 ou inferior, consulte a documentação do 1.x
.
Consulte o guia de atualização para obter informações sobre como atualizar para a versão mais recente.
Escrevi uma postagem no blog sobre o uso do laravel-enum: https://sampo.co.uk/blog/using-enums-in-laravel
Requer PHP 8 e Laravel 9 ou 10.
compositor requer bensampo/laravel-enum
PHP 8.1 suporta enums nativamente. Você pode migrar seus usos de BenSampoEnumEnum
para enums PHP nativos usando as etapas a seguir.
Certifique-se de atender aos seguintes requisitos:
PHP 8.1 ou superior
Laravel 10 ou superior
Rector 0.17 ou superior, seu rector.php
inclui todos os arquivos relevantes
Versão mais recente desta biblioteca
Dependendo do tamanho do seu projeto, você pode optar por migrar todas as enumerações de uma vez ou migrar apenas algumas ou uma enumeração por vez.
Converta todos os enums de uma vez: php artisan enum:to-native
Passe o nome de classe totalmente qualificado de um enum para limitar a conversão: php artisan enum:to-native "AppEnumsUserType"
Isto é necessário se algum enum for usado durante a fase de bootstrap do Laravel, a conversão de seus usos interferir no Larastan e impedir que uma segunda execução do Rector funcione.
Revise e valide as alterações de código para casos extremos perdidos:
Veja não implementado
Enum::coerce()
: Se apenas valores foram passados, você pode substituí-los por tryFrom()
. Se chaves ou instâncias também puderem ser passadas, talvez você precise de lógica adicional para cobrir isso.
Enum::$description
e Enum::getDescription()
: Implemente uma alternativa.
blocos try/catch que manipulam BenSampoEnumExceptionsInvalidEnumKeyException
ou BenSampoEnumExceptionsInvalidEnumMemberException
. Capture o ValueError
lançado por enumerações nativas ou mude para tryFrom()
e manipule null
.
Depois que todas as enumerações forem convertidas, você poderá remover sua dependência desta biblioteca.
Navegue e faça download de uma lista de enums comumente usados e contribuídos pela comunidade.
Biblioteca Enum →
Você pode usar o seguinte comando Artisan para gerar uma nova classe enum:
php artesão make:enum UserType
Agora, você só precisa adicionar os valores possíveis que seu enum pode ter como constantes.
<?php declare(strict_types=1);namespace AppEnums;use BenSampoEnumEnum;classe final UserType estende Enum {const Administrador = 0;const Moderador = 1;const Assinante = 2;const SuperAdministrador = 3; }
É isso! Observe que como os valores enum são definidos como constantes simples, você pode simplesmente acessá-los como qualquer outra constante de classe.
UserType::Administrator // Tem valor 0
Pode ser útil instanciar enums para passá-los entre funções com o benefício da dica de tipo.
Além disso, é impossível instanciar um enum com um valor inválido, portanto você pode ter certeza de que o valor passado é sempre válido.
Por conveniência, enums podem ser instanciados de várias maneiras:
// Nova classe PHP padrão, passando o valor enum desejado como um parâmetro$enumInstance = new UserType(UserType::Administrator);// Igual ao construtor, instanciado por value$enumInstance = UserType::fromValue(UserType::Administrator) ;// Use uma chave enum em vez de seu valor$enumInstance = UserType::fromKey('Administrator');// Chamando estaticamente o nome da chave como um método, utilizando __callStatic magic$enumInstance = UserType::Administrator();// Tentativa de instanciar um novo Enum usando a chave ou valor fornecido. Retorna nulo se o Enum não puder ser instanciado.$enumInstance = UserType::coerce($someValue);
Se quiser que seu IDE preencha automaticamente os auxiliares de instanciação estática, você pode gerar anotações PHPDoc por meio de um comando artesão.
Por padrão, todos os Enums em app/Enums
serão anotados (você pode alterar a pasta passando um caminho para --folder
).
php artesão enum:anotar
Você pode anotar uma única classe especificando o nome da classe.
php artesão enum:annotate "AppEnumsUserType"
Depois de ter uma instância enum, você pode acessar key
, value
e description
como propriedades.
$userType = UserType::fromValue(UserType::SuperAdministrator);$userType->key; // SuperAdministrator$userType->value; // 3$userType->descrição; //Superadministrador
Isso é particularmente útil se você estiver passando uma instância de enum para uma visualização blade.
Instâncias Enum podem ser convertidas em strings à medida que implementam o método mágico __toString()
.
Isso também significa que eles podem ser ecoados em visualizações blade, por exemplo.
$userType = UserType::fromValue(UserType::SuperAdministrator); (string) $userType // '3'
Você pode verificar a igualdade de uma instância em relação a qualquer valor, passando-a para o método is
. Por conveniência, existe também um método isNot
que é exatamente o inverso do método is
.
$admin = UserType::Administrator();$admin->is(UserType::Administrator); // true$admin->is($admin); // true$admin->is(UserType::Administrator()); // true$admin->is(UserType::Moderator); // false$admin->is(UserType::Moderator()); // false$admin->is('valor aleatório'); // falso
Você também pode verificar se o valor da instância corresponde a uma matriz de valores possíveis usando o método in
e usar notIn
para verificar se o valor da instância não está em uma matriz de valores. Iteráveis também podem ser verificados.
$admin = UserType::Administrator();$admin->in([UserType::Moderator, UserType::Administrator]); // true$admin->in([UserType::Moderator(), UserType::Administrator()]); // true$admin->in([UserType::Moderator, UserType::Subscriber]); // false$admin->in(['valor aleatório']); // false$admin->notIn([UserType::Moderator, UserType::Administrator]); // false$admin->notIn([UserType::Moderator(), UserType::Administrator()]); // false$admin->notIn([UserType::Moderator, UserType::Subscriber]); // true$admin->notIn(['valor aleatório']); // verdadeiro
As enumerações instanciadas não são singletons; em vez disso, um novo objeto é criado a cada vez. Assim, a comparação estrita ===
de diferentes instâncias de enum sempre retornará false
, não importa o valor. Por outro lado, a comparação solta ==
dependerá do valor.
$admin = UserType::Administrator();$admin === UserType::Administrator(); // falseUserType::Administrator() === UserType::Administrator(); // false$admin === UserType::Moderator(); // falso$admin === $admin; // true$admin == UserType::Administrator(); // true$admin == UserType::Administrador; // true$admin == UserType::Moderator(); // false$admin == UserType::Moderator; // falso
Um dos benefícios das instâncias enum é que ela permite usar dicas de tipo, conforme mostrado abaixo.
função canPerformAction(UserType $userType) {if ($userType->is(UserType::SuperAdministrator)) {return true; }retornar falso; }$userType1 = UserType::fromValue(UserType::SuperAdministrator);$userType2 = UserType::fromValue(UserType::Moderator);canPerformAction($userType1); // Retorna truecanPerformAction($userType2); //Retorna falso
As enumerações padrão representam um único valor por vez, mas as enumerações sinalizadas ou bit a bit são capazes de representar vários valores simultaneamente. Isso os torna perfeitos para quando você deseja expressar múltiplas seleções de um conjunto limitado de opções. Um bom exemplo disso seriam as permissões de usuário, onde há um número limitado de permissões possíveis, mas um usuário pode ter nenhuma, algumas ou todas elas.
Você pode criar uma enumeração sinalizada usando o seguinte comando artesão:
php artisan make:enum UserPermissions --flagged
Ao definir valores você deve usar potências de 2, a maneira mais fácil de fazer isso é usando o operador shift left <<
assim:
classe final UserPermissions estende FlaggedEnum {const ReadComments = 1 << 0;const WriteComments = 1 << 1;const EditComments = 1 << 2;const DeleteComments = 1 << 3;// O próximo seria `1 << 4` e assim por diante. ..}
Você pode usar bit a bit ou |
para definir um valor de atalho que representa um determinado conjunto de valores.
classe final UserPermissions estende FlaggedEnum {const ReadComments = 1 << 0;const WriteComments = 1 << 1;const EditComments = 1 << 2;const DeleteComments = 1 << 3;// Shortcutsconst Member = self::ReadComments | self::WriteComments; // Ler e escrever.const Moderator = self::Member | self::EditComments; // Todas as permissões que um membro possui, mais Edit.const Admin = self::Moderator | self::DeleteComments; // Todas as permissões que um moderador possui, mais Excluir.}
Existem algumas maneiras de instanciar uma enumeração sinalizada:
// Nova classe PHP padrão, passando os valores enum desejados como um array de valores ou array de instâncias enum$permissions = new UserPermissions([UserPermissions::ReadComments, UserPermissions::EditComments]);$permissions = new UserPermissions([UserPermissions: :ReadComments(), UserPermissions::EditComments()]);// Método de flags estáticos, novamente passando os valores de enum desejados como um array de valores ou array de enum instâncias$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::EditComments]);$permissions = UserPermissions::flags([UserPermissions::ReadComments(), UserPermissions::EditComments()]);
A conversão de atributos funciona da mesma maneira que enumerações de valor único.
Enums sinalizados não podem conter nenhum valor. Cada enum sinalizado possui uma constante predefinida None
que é comparável a 0
.
UserPermissions::flags([])->value === UserPermissions::None; // Verdadeiro
Além dos métodos de enum padrão, há um conjunto de métodos úteis disponíveis em enums sinalizados.
Nota: Em qualquer lugar onde uma propriedade estática for passada, você também poderá passar uma instância de enum.
Defina os sinalizadores do enum para a matriz de sinalizadores fornecida.
$permissions = UserPermissions::flags([UserPermissions::ReadComments]);$permissions->flags([UserPermissions::EditComments, UserPermissions::DeleteComments]); // Os sinalizadores agora são: EditComments, DeleteComments.
Adicione o sinalizador fornecido ao enum
$permissions = UserPermissions::flags([UserPermissions::ReadComments]);$permissions->addFlag(UserPermissions::EditComments); // Os sinalizadores agora são: ReadComments, EditComments.
Adicione os sinalizadores fornecidos ao enum
$permissions = UserPermissions::flags([UserPermissions::ReadComments]);$permissions->addFlags([UserPermissions::EditComments, UserPermissions::WriteComments]); // Os sinalizadores agora são: ReadComments, EditComments, WriteComments.
Adicione todos os sinalizadores ao enum
$permissions = UserPermissions::flags([UserPermissions::ReadComments]);$permissions->addAllFlags(); // Enum agora tem todas as flags
Remova o sinalizador fornecido do enum
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]);$permissions->removeFlag(UserPermissions::ReadComments); // Os sinalizadores agora são: WriteComments.
Remova os sinalizadores fornecidos do enum
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments, UserPermissions::EditComments]);$permissions->removeFlags([UserPermissions::ReadComments, UserPermissions::WriteComments]); // Os sinalizadores agora são: EditComments.
Remova todos os sinalizadores do enum
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]);$permissions->removeAllFlags();
Verifique se o enum possui o sinalizador especificado.
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]);$permissions->hasFlag(UserPermissions::ReadComments); // True$permissions->hasFlag(UserPermissions::EditComments); //Falso
Verifique se o enum possui todos os sinalizadores especificados.
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]);$permissions->hasFlags([UserPermissions::ReadComments, UserPermissions::WriteComments]); // True$permissions->hasFlags([UserPermissions::ReadComments, UserPermissions::EditComments]); //Falso
Verifique se o enum não possui o sinalizador especificado.
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]);$permissions->notHasFlag(UserPermissions::EditComments); // True$permissions->notHasFlag(UserPermissions::ReadComments); //Falso
Verifique se o enum não possui nenhum dos sinalizadores especificados.
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]);$permissions->notHasFlags([UserPermissions::ReadComments, UserPermissions::EditComments]); // True$permissions->notHasFlags([UserPermissions::ReadComments, UserPermissions::WriteComments]); //Falso
Retorne os sinalizadores como uma matriz de instâncias.
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]);$permissions->getFlags(); // [UserPermissions::ReadComments(), UserPermissions::WriteComments()];
Verifique se há vários sinalizadores definidos na enumeração.
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]);$permissions->hasMultipleFlags(); // True;$permissions->removeFlag(UserPermissions::ReadComments)->hasMultipleFlags(); //Falso
Obtenha a máscara de bits para o enum.
UserPermissions::Member()->getBitmask(); // 11;UserPermissions::Moderator()->getBitmask(); // 111;UserPermissions::Admin()->getBitmask(); // 1111;UserPermissions::DeleteComments()->getBitmask(); //1000;
Para usar enums sinalizados diretamente em suas consultas do Eloquent, você pode usar o traço QueriesFlaggedEnums
em seu modelo, que fornece os seguintes métodos:
User::hasFlag('permissões', UserPermissions::DeleteComments())->get();
User::notHasFlag('permissions', UserPermissions::DeleteComments())->get();
User::hasAllFlags('permissions', [UserPermissions::EditComment(), UserPermissions::ReadComment()])->get();
User::hasAnyFlags('permissions', [UserPermissions::DeleteComments(), UserPermissions::EditComments()])->get();
Você pode converter atributos de modelo para enums usando a conversão personalizada integrada do Laravel. Isso converterá o atributo em uma instância de enum ao obter e retornar ao valor de enum durante a configuração. Como Enum::class
implementa o contrato Castable
, você só precisa especificar o nome da classe do enum:
use BenSampoEnumTestsEnumsUserType;use IlluminateDatabaseEloquentModel;class Exemplo estende modelo {protected $casts = ['random_flag' => 'boolean', // Exemplo laravel padrão cast'user_type' => UserType::class, // Exemplo enum cast]; }
Agora, quando você acessa o atributo user_type
do seu modelo Example
, o valor subjacente será retornado como uma enumeração UserType
.
$example = Exemplo::first();$example->user_type // Instância de UserType
Revise os métodos e propriedades disponíveis nas instâncias enum para aproveitar ao máximo a conversão de atributos.
Você pode definir o valor passando o valor enum ou outra instância enum.
$example = Exemplo::first();// Definir usando enum value$example->user_type = UserType::Moderator;// Definir usando enum instance$example->user_type = UserType::Moderator();
$model->toArray()
Ao usar toArray
(ou retornar modelo/modelos do seu controlador como resposta), o Laravel chamará o método toArray
na instância enum.
Por padrão, isso retornará apenas o valor em seu tipo nativo. Você também pode querer ter acesso a outras propriedades (chave, descrição), por exemplo, para retornar ao aplicativo javascript.
Para personalizar esse comportamento, você pode substituir o método toArray
na instância enum.
// Exemplo de classe Enumfinal UserType estende Enum {const ADMINISTRADOR = 0;const MODERADOR = 1; }$instance = UserType::Moderator();// Função pública padrão toArray() {retornar $este->valor; }// Retorna int(1)// Retorna todas as propriedades da função pública toArray() {retornar $isto; }// Retorna um array de todas as propriedades// array(3) {// ["value"]=>// int(1)"// ["key"]=>// string(9) "MODERATOR "// ["descrição"]=>// string(9) "Moderador"// }
Muitos bancos de dados retornam tudo como strings (por exemplo, um número inteiro pode ser retornado como string '1'
). Para reduzir o atrito para os usuários da biblioteca, usamos coerção de tipo para descobrir o valor pretendido. Se preferir controlar isso, você pode substituir o método estático parseDatabase
em sua classe enum:
classe final UserType estende Enum {const Administrador = 0;const Moderador = 1;função estática pública parseDatabase($value) {return (int) $valor; } }
Retornar null
do método parseDatabase
fará com que o atributo no modelo também seja null
. Isso pode ser útil se o seu banco de dados armazenar valores em branco inconsistentes, como strings vazias, em vez de NULL
.
Se você estiver convertendo atributos em seu modelo para enums, o pacote laravel-ide-helper pode ser usado para gerar automaticamente docblocks de propriedades para você.
Como as enumerações impõem consistência no nível do código, não é necessário fazê-lo novamente no nível do banco de dados; portanto, o tipo recomendado para colunas do banco de dados é string
ou int
dependendo dos valores da enumeração. Isso significa que você pode adicionar/remover valores enum em seu código sem se preocupar com a camada de banco de dados.
use AppEnumsUserType;use IlluminateSupportFacadesSchema;use IlluminateDatabaseSchemaBlueprint;use IlluminateDatabaseMigrationsMigration;class CreateUsersTable estende a migração {/** * Execute as migrações. * * @return void */função pública up(): void{ Esquema::table('users', function (Blueprint $table): void {$table->bigIncrements('id');$table->timestamps();$table->string('type') ->default(UserType::Moderador); }); } }
enum
Alternativamente, você pode usar classes Enum
em suas migrações para definir colunas enum. Os valores enum devem ser definidos como strings.
use AppEnumsUserType;use IlluminateSupportFacadesSchema;use IlluminateDatabaseSchemaBlueprint;use IlluminateDatabaseMigrationsMigration;class CreateUsersTable estende a migração {/** * Execute as migrações. * * @return void */função pública up(): void{ Esquema::table('users', function (Blueprint $table): void {$table->bigIncrements('id');$table->timestamps();$table->enum('type', UserType:: getValores()) ->default(UserType::Moderador); }); } }
Você pode validar se um valor enum passado para um controlador é um valor válido para um determinado enum usando a regra EnumValue
.
usar BenSampoEnumRulesEnumValue;armazenamento de função pública(Request $request) {$this->validate($request, ['user_type' => ['required', new EnumValue(UserType::class)], ]); }
Por padrão, a verificação de tipo é definida como estrita, mas você pode ignorar isso passando false
para o segundo parâmetro opcional da classe EnumValue.
new EnumValue(UserType::class, false) // Desativa a verificação estrita de tipo.
Você também pode validar chaves usando a regra EnumKey
. Isso é útil se você usar a chave enum como um parâmetro de URL para classificação ou filtragem, por exemplo.
usar BenSampoEnumRulesEnumKey;armazenamento de função pública(Request $request) {$this->validate($request, ['user_type' => ['required', new <span class="pl-v"