Desenvolvimento

1 fev, 2019

Como criar um pacote para o Laravel

Publicidade

Já se pegou em uma situação onde você está repetindo código? Por exemplo, você inicia um projeto e faz um formulário de contato que envia um e-mail e, então, finaliza e entrega esse projeto. Mas após alguns dias, você começa um novo projeto que também precisa de um formulário de contato. O que você faria? Copiaria o código do projeto já entregue para evitar retrabalho? Com certeza seria uma boa solução. 01 Hoje ensinarei como criar um pacote para o Laravel.

Introdução

Um pacote Laravel é um conjunto de classes reutilizáveis ​​criadas para adicionar funcionalidade extras ao seu projeto. Em termos mais claros, um pacote é para o Laravel, o que os plugins são para o WordPress. O principal objetivo dos pacotes do Laravel é reduzir o tempo de desenvolvimento, tornando os recursos reutilizáveis ​​em um conjunto de classes autônomas que podem ser usadas em qualquer projeto Laravel.

Neste tutorial, vamos construir um formulário de contato do pacote Laravel e publicá-lo no Packagist.

Pré-requisitos

Para seguir este tutorial, você deve ter:

  • Conhecimento básico do Laravel v5.5 ou superior
  • Composer instalado em sua máquina. Se você não tem o Composer instalado em seu sistema, você pode baixá-lo aqui

Começando

Como um pacote é criado para adicionar funcionalidade extra a um projeto Laravel, a primeira coisa que precisamos fazer é criar um. Vamos configurá-lo usando o Composer. Para outros métodos de instalação, você pode verificar a documentação oficial do Laravel aqui.

composer create-project --prefer-dist laravel/laravel meu_primeiro_pacote

Quando estiver pronto, você precisa configurar seu arquivo .env e definir sua chave de aplicativo e outros detalhes necessários. No diretório raiz do seu projeto, em seu terminal, execute:

cp .env.example .env

Ou copie manualmente o conteúdo de .env.example e salve-o em um novo arquivo como .env. Então, digite:

php artisan key:generate

Depois de gerar sua chave e configurar os detalhes do seu banco de dados, o seu .env deve ter esta aparência:

APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:uynE8re8ybt2wabaBjqMwQvLczKlDSQJHCepqxmGffE=
APP_DEBUG=true
APP_URL=http://localhost
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=nome_do_banco_de_dados
DB_USERNAME=usuario_do_banco_de_dados
DB_PASSWORD=senha_do_banco_de_dados
BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

Neste ponto, nosso projeto básico do Laravel está configurado e é hora de iniciar o desenvolvimento do nosso pacote.

Criando o esqueleto do pacote

Vamos criar a estrutura de pastas do nosso pacote. Existem basicamente duas maneiras de fazer isso: através do método de criação de arquivos e pastas individuais ou usando um pacote, como por exemplo, essa ferramenta para o terminal. Vamos criar manualmente os arquivos e pastas para que possamos entender melhor como cada peça se encaixa.

Primeiro, precisamos criar a estrutura de pastas para o nosso pacote.

A partir do diretório raiz, crie pastas com essa estrutura:

packages/MyVendor/MeuPacote/

Todo o nosso desenvolvimento acontecerá dentro da pasta packages/MyVendor/MyPacote/ em vez de vendor/MyVendor/MyPacote/, porque não é uma boa prática alterar o código na pasta do vendor. Quando terminarmos de publicar nosso pacote, ele será baixado para a pasta de vendor automaticamente.

  • MyVendor significa o nome do fornecedor, que pode ser seu nome, o nome do seu cliente ou organização para a qual você está criando o pacote.
  • MyPackage significa o nome do pacote. No nosso caso, será “formulario-contato”.

Agora, vamos criar os arquivos e pastas que compõem o nosso pacote:

MyVendor
        └── formulario-contato
            └── src
                ├── database
                │   └── migrations
                ├── Http
                │   └── controllers
                ├── Models
                ├── resources
                │   └── views
                └── routes

Agora que nossas pastas estão configuradas, precisamos inicializar o Composer, para que o nosso pacote possa ser baixado em nossa pasta vendor mais tarde. Na raiz do seu pacote, abra um terminal e execute:

composer init

Como é interativo, ele fará várias perguntas que serão usadas para preencher o arquivo composer.json. Siga as instruções do composer, se você não souber como responder, pressione Enter para usar a resposta padrão ou altere-a mais tarde diretamente no composer.json gerado. Agora, o seu composer.json deve ficar assim:

Note que você pode alterar “MyVendor” no código abaixo com o nome do seu próprio fornecedor. No entanto, certifique-se de alterar o nome do fornecedor em todos os lugares em que for chamado.

{
        "name": "MyVendor/FormularioContato",
        "description": "Um pacote que cria formulários de contato para o Laravel",
        "authors": [{
            "name": "Douglas Men",
            "email": "douglas@programandocomphp.com.br"
        }],
        "require": {}
    }

Em nosso composer.json, precisamos dizer para autoload de onde carregar nossos arquivos. Adicione este código ao seu composer.json:

"autoload": {
            "psr-4": {
                "MyVendor\\formulario-contato\\": "src/"
            }
        }

Neste ponto, nosso arquivo composer.json deve estar assim:

{
        "name": "MyVendor/FormularioContato",
        "description": "Um pacote que cria formulários de contato para o Laravel",
        "authors": [{
            "name": "Douglas Men",
            "email": "douglas@programandocomphp.com.br"
        }],
        "require": {},
        "autoload": {
            "psr-4": {
                "MyVendor\\formulario-contato\\": "src/"
            }
        }
    }

Uma vez feito isso, crie um repositório git vazio para acompanhar as mudanças (nós adicionaremos o repositório remoto mais tarde). No seu terminal, execute:

git init

Dando vida ao nosso pacote

Vamos adicionar arquivos ao nosso pacote. Primeiro, precisamos definir um provedor de serviços (ServiceProvider) para o nosso pacote. Um provedor de serviços é o que o Laravel usa para determinar os arquivos que serão carregados e acessados ​​pelo seu pacote.

Na sua pasta src /, crie um arquivo chamado FormularioContatoServiceProvider.php! A estrutura deve ficar assim:

src/FormularioContatoServiceProvider.php

Dentro do nosso provedor de serviços, precisamos definir algumas coisas:

  • O namespace (que definimos no nosso autoload composer.json)
  • A extensão (a classe de Laravel que nosso provedor de serviço estende)
  • Os dois métodos obrigatórios que todos os provedores de serviços devem ter (cada provedor de serviços do pacote Laravel deve ter pelo menos dois métodos: boot () e register ())

Dentro da classe do provedor de serviços, adicione as seguintes linhas de código abaixo.

Mas antes, note que você pode substituir MyVendor no código abaixo com o nome do seu próprio fornecedor. No entanto, certifique-se de alterar o nome do fornecedor em todos os lugares em que for chamado.

<?php
// MyVendor\formulario-contato\src\FormularioContatoServiceProvider.php
namespace MyVendor\FormularioContato;
use Illuminate\Support\ServiceProvider;
class FormularioContatoServiceProvider extends ServiceProvider 
{
    public function boot()
    {
    }
    public function register()
    {
    }
}

Como não implantamos nosso pacote e ele ainda não está dentro da nossa pasta vendor, precisamos informar ao Laravel como carregar nosso pacote e usá-lo, então, dentro da raiz do seu aplicativo Laravel no composer.json, adicione este código:

"autoload": {
            "classmap": [
                "database/seeds",
                "database/factories"
            ],
            "psr-4": {
                "MyVendor\\FormularioContato\\": "packages/MyVendor/formulario-contato/src",
                "App\\": "app/"
            }
        },
        "autoload-dev": {
            "psr-4": {
                "MyVendor\\FormularioContato\\": "packages/MyVendor/formulario-contato/src",
                "Tests\\": "tests/"
            }
        },

Note que você pode substituir MyVendor no código acima com o nome do seu próprio fornecedor. No entanto, certifique-se de alterar o nome do fornecedor em todos os lugares em que for chamado.

Dependendo da versão do seu Laravel, o arquivo composer.json pode sofrer essas alterações automaticamente. Certifique-se de pular essa etapa se isso acontecer.

Depois disso, no seu terminal, na raiz do seu projeto, execute:

composer dump-autoload

Agora, vamos testar e ver se nosso pacote está sendo carregado corretamente. Dentro do método de inicialização do seu FormularioContatoServiceProvider.php, vamos adicionar uma rota e carregá-la:

// MyVendor\formulario-contato\src\FormularioContatoServiceProvider.php
$this->loadRoutesFrom(__DIR__.'/routes/web.php'

Note que:

  • __DIR__ refere-se ao diretório atual onde o arquivo está
  • routes/web.php se refere à pasta de rotas que devemos criar para o nosso pacote, que ficará na pasta src, não nas rotas padrão do Laravel

Em nossa pasta de rotas do pacote, adicione o arquivo web.php e adicione o seguinte código a ele:

<?php
// MyVendor\formulario-contato\src\routes\web.php
Route::get('contato', function(){
    return 'Hello World do seu Pacote!';
});

Em seguida, precisamos adicionar nosso novo provedor de serviços no arquivo, que fica localizado em config/app.php, dentro da raiz do projeto:

// config/app.php
'providers' => [
     ...,
     App\Providers\RouteServiceProvider::class,
     // Our new package class
     MyVendor\FormularioContato\FormularioContatoServiceProvider::class,
 ],

Agora, inicie seu aplicativo Laravel usando:

php artisan serve

No seu navegador, navegue até localhost: 8000/contato e você verá isto:

Agora, sabemos que nosso pacote está carregando corretamente. Com isso, precisamos criar nosso formulário de contato. Para fazer isso, devemos criar a view e dizer ao Laravel como carregá-la. Em seu método boot(), digite o seguinte:

// MyVendor\contactform\src\ContactFormServiceProvider.php
$this->loadViewsFrom(__DIR__.'/resources/views', 'formulario-contato');

Resources/views referem-se à pasta de recursos que criamos para o nosso pacote e não à pasta de recursos padrão do Laravel.

Para distinguir entre as visualizações padrão do Laravel e as visualizações de pacotes, temos que adicionar um parâmetro extra à nossa função loadviewsfrom() e esse parâmetro extra deve ser o nome do seu pacote. No nosso caso, é o formulário de contato. Então, agora, sempre que queremos carregar uma view, referenciamos com esta convenção de sintaxe packagename :: view.

Criando a estrutura HTML

Agora, vamos criar nosso formulário de contato e adicionar a funcionalidade. Em sua pasta resources/views, crie um arquivo chamado contato.blade.php e adicione as seguintes linhas de código:

<!-- MyVendor\formulario-contato\src\resources\views\contato.blade.php -->
    <!DOCTYPE html>
    <html lang="pt-BR">
    <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
          <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
          <title>Entre em Contato</title>
    </head>
        <body>
          <div style="width: 500px; margin: 0 auto; margin-top: 90px;">
            @if(session('status'))
                <div class="alert alert-success">
                    {{ session('status') }}
                </div>
            @endif
          <h3>Entre em Contato</h3>
          <form action="{{route('contato')}}" method="POST">
              @csrf
              <div class="form-group">
                <label for="inputExemplo1">Seu Nome</label>
                <input type="text" class="form-control" name="nome" id="inputExemplo1" placeholder="Seu Nome">
              </div>
              <div class="form-group">
                <label for="inputExemplo2">Email</label>
                <input type="email" class="form-control" name="email" id="inputExemplo2" placeholder="nome@email.com.br">
              </div>
              <div class="form-group">
                <label for="textAreaExemplo1">Digite sua Mensagem</label>
                <textarea class="form-control"name="mensagem" id="textAreaExemplo1" rows="3"></textarea>
              </div>
              <button type="submit" class="btn btn-primary">Enviar</button>
         </form>
        </div>
    </body>
    </html>

Na ação de nosso formulário, nós definimos a rota “contato” e escolhemos o método POST. Agora, precisamos definir esta rota em routes/web.php:

// MyVendor\formulario-contato\src\routes\web.php
Route::get('contato', function(){
    return view('formulario-contato::contato');
});
Route::post('contato', function(){
   // ...
})->name('contato');

Já podemos visitar o localhost: 8000/contato e veremos:

Nosso arquivo routes/web.php já possui um trecho de código que, por convenção, deve estar em um controlador (Controller). Então, precisamos mover nossa lógica para nossos arquivos de controle. Primeiro, precisamos criar o arquivo em uma nova pasta Http/Controllers /. Crie um arquivo chamado FormularioContatoController.php e, dentro dele, vamos criar dois métodos. Um para mostrar a página e o outro para enviar o e-mail. Dentro do FormularioContatoController.php, adicione o seguinte código:

    <?php
    // MyVendor\formulario-contato\src\Http\Controllers\FormularioContatoController.php
    namespace MyVendor\FormularioContato\Http\Controllers;
    use App\Http\Controllers\Controller;
    use Illuminate\Http\Request;
    use MyVendor\FormularioContato\Models\FormularioContato;
    class FormularioContatoController extends Controller {
        public function index()
        {
           return view('formulario-contato::contato');
        }
        public function enviarEmail(Request $request)
        {
            FormularioContato::create($request->all());
            return redirect(route('contato'));
        }
    }

Agora, mude o código no seu arquivo routes/web.php para:,

    <?php
    // MyVendor\formulario-contato\src\routes\web.php
    Route::group(['namespace' => 'MyVendor\FormularioContato\Http\Controllers', 'middleware' => ['web']], function(){
        Route::get('contato', 'FormularioContatoController@index');
        Route::post('contato', 'FormularioContatoController@sendMail')->name('contato');
    });

Se você tentar carregar a rota sem o namespace, o Laravel acusará um erro porque, por padrão, procura na raiz da pasta. Então, o namespace é adicionado para dizer exatamente de onde carregar.

Agora, vamos criar um modelo que nos ajude a relacionar com o banco de dados e algumas migrações ao lado. Dentro da pasta “Models”, crie um arquivo chamado FormularioContato.php e adicione o seguinte código:

<?php
    // MyVendor\formulario-contato\src\Models\FormularioContato.php
    namespace MyVendor\FormularioContato\Models;
    use Illuminate\Database\Eloquent\Model;
    class FormularioContato extends Model
    {
        protected $guarded = [];
        protected $table = 'contatos';
    }

Criemos nossa migração para que possamos salvar os detalhes dos usuários. Primeiro, crie o caminho da pasta database/migrations na pasta src do seu pacote. Dentro do seu terminal, a partir do diretório base do seu aplicativo, execute este comando:

php artisan make:migration create_contatos_table --path=packages/MyVendor/formularios-contato/src/database/migrations --create=contatos

Note que você pode substituir MyVendor no código abaixo com o nome do seu próprio fornecedor. No entanto, certifique-se de alterar o nome do fornecedor em todos os lugares em que for chamado.

Em sua pasta de migrações, encontra a migration recém-criada e adicione as seguintes linhas de código a ela:

    <?php
    // // MyVendor\Contactform\src\Database\migrations\*_create_contatos_table.php
    use Illuminate\Support\Facades\Schema;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Database\Migrations\Migration;
    class CreateContatosTable extends Migration
    {
        /**
         * Run the migrations.
         *
         * @return void
         */
        public function up()
        {
            Schema::create('contatos', function (Blueprint $table) {
                $table->increments('id');
                $table->string('nome');
                $table->string('email');
                $table->text('mensagem');
                $table->timestamps();
            });
        }
        /**
         * Reverse the migrations.
         *
         * @return void
         */
        public function down()
        {
            Schema::dropIfExists('contatos');
        }
    }

Agora, precisamos executar nossa migração. Por padrão, o Laravel carrega as migrações do diretório base, portanto, temos que carregar as migrações do pacote para que o Laravel entenda. Dentro da pasta de seu pacote, no arquivo
FormularioContatoServiceProvider.php, adicione a seguinte linha na função boot():

// MyVendor\formulario-contato\src\FormularioContatoServiceProvider.php
$this->loadMigrationsFrom(__DIR__.'/database/migrations');

Agora, em seu terminal, execute:

php artisan migrate

Esse comando criará as tabelas em seu banco de dados.

Salvando o e-mail no banco de dados

Vamos enviar o e-mail e salvá-lo no banco de dados. No arquivo FormularioContatoController.php, adicione essas linhas ao método enviarEmail:

    // MyVendor\formulario-contato\src\Http\Controllers\FormularioContatoController.php
     
    public function enviarEmail(Request $request)
        {
            FormularioContato::create($request->all());
            return redirect(route('contato'));
        }

Agora, vá para a rota /contato no seu navegador e envie um e-mail; ele será inserido em seu banco de dados.

Adicionando uma mensagem flash de sucesso

Embora tenhamos certeza de que nosso formulário de contato seja salvo com sucesso, será um bom gesto mostrar uma pequena mensagem aos nossos usuários informando que o e-mail foi enviado com sucesso.

Em nosso método EnviarEmail, vamos substituir a declaração de retorno com isto:

return redirect(route('contato'))->with(['mensagem' => 'Obrigado! Seu e-mail foi enviado com sucesso.']);

Em nossa view, antes da declaração do formulário, vamos imprimir a mensagem quando tivermos uma:

<!-- MyVendor\formulario-contato\src\resources\views\contato.blade.php -->
    @if(Session::has('mensagem'))
       {{Session::get("mensagem")}}
    @endif

Tenho que assumir, não foi fácil escrever este artigo; mas tenho certeza de que será de grande utilidade para você, caro leitor.

Faça a instalação de um novo Projeto Laravel, construa seu pacote e mande para douglas@programandocomphp.com.br, estou curioso para ver os resultados.