Back-End

19 fev, 2016

Desenvolvendo uma aplicação web com Lumen e MySQL

Publicidade

O Lumen é um novo microframework PHP desenvolvido por Taylor Otwell, o mesmo autor do famoso framework Laravel. Eu quis lhe dar uma chance e estou aqui para compartilhar as minhas experiências. Não sou um especialista em Lumen (ainda), mas acho que uma das melhores características desse framework é que ele torna realmente muito fácil iniciar um novo projeto. Então, para provar isso, vamos agora construir um aplicativo totalmente funcional suportado por um banco de dados MySQL em menos de 30 minutos. Você está pronto para começar?

Uma frase motivacional diária

Nosso aplicativo deve ser bastante simples, mas eu gostaria também de fazer algo útil. Sou um grande fã de citações motivacionais, e se você me segue no Twitter (você deve!), provavelmente já sabe!

Assim, a ideia é construir um aplicativo web que mostra uma citação nova diariamente. Dessa forma, todos os dias, quando você acordar, pode executar o aplicativo e ser inspirado e motivado por uma frase sábia e energizante para fazer o seu melhor!

Para trabalhar melhor, nosso aplicativo deve, obviamente, ser extravagante, com muitas imagens legais de fundo, como na imagem abaixo. Isso é um detalhe importante!

motivation-quote-app-screenshoot

Um novo projeto Lumen

Vamos começar. Primeiro de tudo, para criar um novo projeto Lumen, precisamos ter o instalador de linha de comando Lumen. Uma ferramenta muito simples, que usa Composer e que nos permite inicializar um novo projeto Lumen em poucos segundos. Baixe e também certifique-se de ter o Composer instalado globalmente e execute o seguinte comando:

composer global require "laravel/lumen-installer=~1.0"

Nota: você pode precisar usar sudo dependendo da forma como você instalou o Composer.

Uma vez que tenhamos feito isso, temos um novo brinquedo no nosso shell: o comando lumen. Podemos agora criar um novo projeto em execução:

lumen new motivational

motivational é o nome do nosso novo aplicativo. O comando cria uma nova pasta para ele e faz o download de todas as dependências.

Para ver a nossa aplicação funcionar precisamos navegar com cd até o diretório motivational e executar

php artisan serve

Nosso projeto será imediatamente instalado e ficará funcional em http://localhost:8000.

Defina o modelo de dados

Nós dissemos que queremos mostrar citações e, no nosso caso, uma citação é composta por:

  • um texto (o próprio texto citado)
  • um autor (o nome do autor da citação)
  • uma imagem de fundo (sim, para tornar tudo mais chique)

A fim de gerenciar os dados do banco de dados, precisamos habilitar o Eloquent (a biblioteca Lumen/Laravel ORM), configurar a nossa conexão com o banco, criar uma migração e um modelo e, finalmente, semear nossa base de dados. Vamos fazê-lo passo a passo.

Habilite Eloquent

Para habilitar Eloquent, precisamos editar o arquivo bootstrap/app.php e remover o comentário sobre as seguintes linhas:

$app->withFacades();
$app->withEloquent();

Observe que a primeira linha habilita o suporte para Facades (uma feature muito comum usada no Laravel e herdada pelo Lumen) que simplifica o uso de algumas das principais classes do framework.

Configure a conexão de banco de dados

Em primeiro lugar, certifique-se de ter uma instância do MySQL rodando em sua máquina e de ter as credenciais para se conectar a ela. Agora vamos criar nosso arquivo de configuração .env (Dotenv). Copie o arquivo .env.example para um novo .env e abra no seu editor favorito.

Aqui precisamos editar as seguintes linhas e fornecer os detalhes necessários para nos conectarmos à nossa instância mysql local:

DB_CONNECTION=mysql  
DB_HOST=localhost  
DB_DATABASE=homestead  
DB_USERNAME=homestead  
DB_PASSWORD=secret

Certifique-se de criar o banco de dados (homestead, nesse caso, mas você pode personalizá-lo, obviamente).

Em geral, também é uma boa ideia alterar o valor de APP_KEY em alguma sequência aleatória para o caso de você estar criando um aplicativo “sério”.

Para fazer o Lumen carregar esse arquivo de configuração de que precisamos, mais uma vez, edite o arquivo bootstrap/app.php e remova o comentário da seguinte linha:

Dotenv::load(__DIR__.'/../');

Crie uma migração

Migrações permitem que o framework mantenha o esquema de banco sob controle. Elas definem todas as tabelas do banco de dados e campos programaticamente, e acompanham as várias alterações nelas (de modo que podemos facilmente atualizar e reverter todo o esquema quando necessário). Precisamos inicializar o sistema de migração com o comando:

php artisan migrate:install

Esse comando cria uma tabela especial em nosso banco de dados chamada migrations que será usada internamente a partir do framework para manter o controle de todas as migrações disponíveis utilizadas atualmente.

Cada migração é identificada por um arquivo que geralmente está localizado no diretório database/migrations. O arquivo descreve as mudanças em nosso esquema (ex.: novas tabelas, novos campos, novos índices, tabelas a serem excluídas etc.). No nosso caso, precisamos criar uma nova tabela, a tabela “quotes” para ser preciso. Vamos executar este comando:

php artisan make:migration --create=quotes create_quotes_table

Ele cria um novo arquivo com o diretório database/migrations que podemos facilmente editar para adicionar os campos que queremos ter em nossa tabela. Nós só precisamos ajustar a função up() um pouco:

public function up()  
{
    Schema::create('quotes', function(Blueprint $table)
    {
         $table->increments('id');
                     $table->timestamps();         

         // our new fields
                     $table->string('text');
                     $table->string('author');
                     $table->string('background');
    });
}

Para executar a migração (e efetivamente criar a tabela no banco de dados), temos de executar:

php artisan migrate

Crie o modelo Quote

Em geral, um modelo é uma classe usada para abstrair os nossos dados e representá-los como um objeto. Em ORMs, uma classe de modelo também oferece métodos estáticos para consulta e armazenamento de dados para recuperar os dados da fonte de dados e criar os objetos correspondentes.

No nosso caso, precisamos definir o modelo Quote modelo em app/Models/Quote.php:

<?php

# app/Models/Quote.php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

final class Quote extends Model  
{

}

Sim, é isso… nós realmente não precisamos escrever qualquer outra coisa! Estamos ampliando a classe Eloquent Model que faz todo o trabalho duro para nós, provando que uma configuração do modelo padrão é boa o suficiente na maioria das vezes. Nesse caso, ele mapeia automaticamente a classe Quote para a tabela quotes que criamos antes.

Semeie o banco de dados

O processo de semeadura nos permite preencher nosso banco de dados com os dados iniciais. Em nosso caso, podemos usá-lo para fornecer algumas citações. É bastante útil porque não vamos construir um administrador pleno para fazer a entrada de dados nessa fase (e nós também não teremos que tocar no banco de dados manualmente).

Arquivos seeds são armazenados em database/seeds, e precisamos criar um novo arquivo lá. Vamos chamá-lo de QuoteTableSeeder.php.

<?php

# database/seeds/QuoteTableSeeder.php

use App\Models\Quote;  
use Illuminate\Database\Seeder;

class QuoteTableSeeder extends Seeder  
{
    public function run()
    {
        Quote::create([
            'text' => 'Success is going from failure to failure without losing your enthusiasm',
            'author' => 'Winston Churchill',
            'background' => '1.jpg'
        ]);

        Quote::create([
            'text' => 'Dream big and dare to fail',
            'author' => 'Norman Vaughan',
            'background' => '2.jpg'
        ]);

        Quote::create([
            'text' => 'It does not matter how slowly you go as long as you do not stop',
            'author' => 'Confucius',
            'background' => '3.jpg'
        ]);

        //... add more quotes if you want!
    }
}

O código é bastante autoexplicativo: cada chamada a Quote::create insere um novo registro na tabela quotes com os dados fornecidos no array passado como argumento. A única coisa que vale notar é que estamos passando uma referência relativa para um arquivo no campo background. Você precisa ter esses arquivos em sua pasta public/img/, pois isso nos permite enviá-los para o navegador. Se você precisar de algumas boas fotos livres de royalties, dê uma olhada no projeto Unsplash.

Para ativar esse script seed, é preciso vinculá-lo ao script principal DatabaseSeeder, adicionando a seguinte linha dentro do método run():

$this->call('QuoteTableSeeder');

Agora só precisamos executar o seguinte comando para executar o script seed e preencher o banco de dados:

php artisan db:seed

Puxa vida, temos como retorno um Class QuoteTableSeeder does not exist! É por isso que, por padrão, o arquivo Composer do Lumen mapeia o caminho de database com a estratégia classmap. Isso significa que cada vez que o Composer despeja o autoloader, ele cria um mapa estático de todas as classes disponíveis dentro dessa pasta. Então, cada vez que adicionarmos uma nova classe, não precisamos manualmente re-despejar o script autoloader:

composer dump-autoload

Agora vamos executar novamente o arquivo php artisan db:seed e, desta vez, tudo deve ficar bem.

Se você explorar seu banco de dados, verá alguns registros dentro da tabela quotes.

O routing

Até agora, apenas definimos o modelo de dados do nosso aplicativo e povoamos nosso banco de dados. Agora vamos adicionar um pouco de lógica de negócios e mapeá-la para algumas rotas.

Teremos duas rotas:

  • GET / – a principal via, proporcionando uma citação nova todos os dias
  • GET /{id} – a rota de uma citação específica, mapeada por id

Para definir a lógica de negócios associada a uma rota, temos de editar o arquivo app/Http/routes.php:

<?php

# app/Http/routes.php

use App\Models\Quote;

/**
 * Display the today quote
 */
$app->get('/', function() use ($app) {

    /*
     * Picks a different quote every day 
     * (for a maximum of 366 quotes)
     *
     *   - $count: the total number of available quotes
     *   - $day: the current day of the year (from 0 to 365)
     *   - $page: the page to look for to retrieve the 
     *            correct record
     */
    $count = Quote::query()->get()->count();
    $day = (int) date('z');
    $page = $day % $count + 1;

    $quotes = Quote::query()->get()->forPage($page, 1)->all();

    if (empty($quotes)) {
        throw new \Illuminate\Database\Eloquent\ModelNotFoundException();
    }

    return view('quote', ['quote' => $quotes[0]]);
});

/**
 * Display a specific quote
 */
$app->get('/{id}', function($id) use ($app) {
    $quote = Quote::query()->findOrFail($id);
    return view('quote', ['quote' => $quote]);
});

Os dois $app->get definem as duas rotas que precisamos para o nosso aplicativo. Para cada rota temos que definir a lógica de negócios dentro de uma função de encapsulamento. O código é muito simples e, graças aos comentários, deve ser bastante fácil de entender.

A função view() permite renderizar um modelo. Nesse caso, estamos renderizando o template quote, passando o modelo como uma variável quote. No parágrafo seguinte, vamos ver como definir o nosso template.

Nota: se você não quiser usar rotas no seu routing e quer ter um maior controle sobre a estrutura de seu código e sua lógica de negócio, poderá aproveitar os controladores do Laravel. Não vou entrar em detalhes sobre isso, mas você pode verificar a documentação que mostra como fazê-lo. É muito simples.

O template

O Lumen usa a linguagem modelo padrão Laravel, Blade. O Blade nos permite processar código HTML complexo de uma forma fácil. Todos os modelos estão na pasta resources/views. Vamos criar o arquivo quote.blade.php:

<!-- resources/views/quote.blade.php -->

<html>  
<head>  
    <title>Motivaitonal — Your daily source of motivation!</title>
    <link href="/css/style.css" rel="stylesheet" type="text/css"/>
    <link href='http://fonts.googleapis.com/css?family=Alegreya:400,700|Roboto+Condensed' rel='stylesheet' type='text/css'>
</head>  
<body style="background-image: url('/img/{{$quote->background}}')">  
<div class="container">  
    <div class="quote-container">
        <p class="text">{{$quote->text}}</p>
        <p class="author">— {{$quote->author}}</p>
    </div>
</div>  
</body>  
</html>

Como você pode ver, podemos usar a sintaxe com dupla de chaves para referenciar valores de variáveis.

Para terminar só precisamos criar o nosso arquivo public/css/style.css de folha de estilos:

html, body {  
    height: 100%;
    padding: 0;
    margin: 0;
}

body {  
    background-size: cover;
}

.container {
    height: 100%;
    background: rgba(0,0,0,.3);
}

.quote-container {
    position: relative;
    top: 50%;
    transform: translateY(-50%);
    padding: 2em 4em;
}

.quote-container p {
    text-align: center;
    color: #fff;
    text-shadow: 1px 1px 1px rgba(150, 150, 150, 0.8);
}

.quote-container p.text {
    font-family: 'Alegreya', serif;
    font-size: 4em;
}

.quote-container p.author {
    font-family: 'Roboto Condensed', sans-serif;
    font-size: 1.2em;
}

É isso, agora o aplicativo está instalado e funcionando. Não é bonito? Hey, deixe-me saber se você decidir publicá-lo e motivar todo o mundo! 😉

Conclusões

O Lumen parece ser um framework muito promissor para a prototipagem rápida de pequenas aplicações web. Estou ansioso para usá-lo novamente para um caso de uso mais complexo onde eu possa adotar outras características interessantes como a camada de cache e a biblioteca enfileiramento de trabalhos.

Você já usou Lumen? Você acha que ele vai se tornar um framework dominante ao longo do Laravel ou ele vai ser apenas mais uma das centenas de frameworks Php disponíveis no mercado? Estou muito curioso para saber o que você pensa sobre isso, deixe-me saber nos comentários!

***

Luciano Mammino faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: http://loige.co/developing-a-web-application-with-lumen-and-mysql/