Criando um comando Artisan personalizado para definir valores de variáveis no .env no Laravel
Tags: laravel, php, terminal, env
Published: 2023-09-07 11:15:52

Olá, dev!

Em algum momento você já precisou definir algum hash dinâmico no seu arquivo .env? Como por exemplo um authorization api da sua aplicação?Não é nada seguro deixar esse hash no .env.exemple em seu repositório do GitHub e é super chato ter que ficar gerando o hash e colando lá toda vez que você vai configurar o projeto, estou certo?

Mas em algum momento você, assim como eu, já deve ter pensado a seguinte frase:
> Seria ótimo se tivesse um comando igual ao de gerar o app_key para a minha variável…

E se eu te disser que tem como?

Primeiramente defina a variável em .env e no .env.exemple para você não perder ela, deixe igual no meu exemplo a seguir.

```
MY_VAR=
```
Apenas isso já vai garantir que o comando jogue o valor do hash nessa variável no .env, ela somente deve existir sem um valor atribuído.

Em seguida, use o seguinte comando na pasta raiz do seu projeto, se for contêiner Decker, rode dentro do contêiner.

```
php artisan make:command MyVarHash --command=key:my-var-hash
```

A explicação para o comando acima é a seguinte: php artisan make:command vai gerar um arquivo no diretório app/Console/commands que é o diretório para os arquivos de comandos personalizados do Laravel. MyVarHash será o nome do arquivo que irá salvar no diretório mencionado e por ultimo, — — command=key:my-var-hash, é o comando que irá rodar esse arquivo, que no nosso exemplo ficará php artisan key:my-var-hash.

Após rodar esse comando, você terá uma classe mais ou menos assim:

```
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class MyVarHashKey extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'key:my-var-hash';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Generate my env key value';

    /**
     * Execute the console command.
     */
    public function handle(): void
    {
        
    }
}

```
Na variável $signature vai ser definido o comando artisan para se rodar, caso queira mudar, aqui é o local. Já a variável $description vai conter a descrição do que o seu comando faz, mostra no php artisan list. No método handle é onde vai ficar o código a ser executado quando rodarmos o comando.

> Neste caso em específico o meu post é para alterar uma chave .env, mas se quiser que faça qualquer outra coisa, é só desenvolver dentro do método handle.

Vamos lá, no método handle vamos desenvolver o seguinte código:

```
    public function handle(): void
    {
        $key = md5(uniqid()) . md5(uniqid());
        if (! $this->setKeyInEnvironmentFile($key)) {
            $this->info('My-var-hash generate error.');
            return;
        }
        $this->laravel['config']['my.var.hash'] = $key;
        $this->info('My-var-hash generate success.');
    }
```
Na variável $key tenho um hash gerado dinamicamente, tendo em vista que é dois md5 de um id único concatenando, ou seja, nunca será igual.

Teremos um método para inserir esse hash no .env que vai retornar um booleano, caso false exibe uma informação de erro e para a execução do método, caso retorne true, define a variável no laravel e exibe uma mensagem de sucesso, também parando a execução do método, já que chegou ao seu fim.

No método setKeyInEnvironmentFile, que vai ser o responsável por inserir o hash na nossa variável do .env, nele encontraremos o código:
```
    protected function setKeyInEnvironmentFile(string $key): bool
    {
        $filepath = $this->laravel->environmentFilePath();
        $input = file_get_contents($filepath);
        $replaced = preg_replace($this->keyReplacementPattern(), 'MY_VAR=' . $key, $input);
        if ($replaced === $input || $replaced === null) {
            $this->error('Unable to set my var key. No MY_VAR variable was found in the .env file.');
            return false;
        }
        file_put_contents($filepath, $replaced);
        return true;
    }
```
Como esse método será executado somente dentro dessa classe, vou defini-lo como protected, recebendo por parâmetro o hash na variável $key. Na variável $filepath iremos trazer a localização do arquivo .env, já na variável $input pegaremos o conteúdo do arquivo .env na variável $replaced vamos fazer o replace da variável vazia que criamos anteriormente, aqui chamaremos outro método para fazer o escape.

Validamos a variável $replaced está igual o $input, ou se está nula, caso essas condições sejam verdadeiras, retorna um erro na tela e para a execução do código, já que reotna false para o primeiro método que vai cortar a execução.

Por fim nesse método teremos a gravação do novo arquivo .env com as alerações já feitas, retornando true para o método inicial.

Assim teremos a classe da seguinte forma:

```
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class MyVarHashKey extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'key:my-var-hash';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Generate my env key value';

    /**
     * Execute the console command.
     */
    public function handle(): void
    {
        $key = md5(uniqid()) . md5(uniqid());
        if (! $this->setKeyInEnvironmentFile($key)) {
            $this->info('My-var-hash generate error.');
            return;
        }
        $this->laravel['config']['my.var.hash'] = $key;
        $this->info('My-var-hash generate success.');
    }

    protected function setKeyInEnvironmentFile(string $key): bool
    {
        $filepath = $this->laravel->environmentFilePath();
        $input = file_get_contents($filepath);
        $replaced = preg_replace($this->keyReplacementPattern(), 'MY_VAR=' . $key, $input);
        if ($replaced === $input || $replaced === null) {
            $this->error('Unable to set my var key. No MY_VAR variable was found in the .env file.');
            return false;
        }
        file_put_contents($filepath, $replaced);
        return true;
    }

    protected function keyReplacementPattern(): string
    {
        $escaped = preg_quote('=' . $this->laravel['config']['my.var.hash'], '/');
        return "/^MY_VAR{$escaped}/m";
    }
}
```
Com isso, basta executar o seu comando artisan e o hash já estará inserido na sua variável dentro do .env, espero que o conteúdo tenha sido útil.

Até mais, dev ;)