fbpx

Introdução ao Laravel Framework – Parte 07: model e banco de dados

Introdução ao Laravel Framework – Parte 07: model e banco de dados

👊😎 Saudações, devs! No último post falamos sobre as views e como usar o Blade, o motor de template do Laravel.

Agora vamos falar sobre como integrar nossa aplicação com um banco de dados relacional.

Bora! 🚀

O que é um objeto model?

Na arquitetura MVC, considerando sua forma mais simples, a camada Model possui os objetos que manipulam os dados da aplicação, a lógica e as regras de negócio.

Esses dados normalmente são tabelas de um banco de dados, mas podem ser qualquer outro tipo de repositório de dados, dependendo da aplicação (arquivos XML, binários, documentos, ontologias, etc).

Assim, os objetos Model são capazes de abstrair a lógica de acesso ao banco de dados, permitindo que o programador concentre-se na aplicação, sem usar comandos SQL em operações CRUD (Create-Read-Update-Delete).

No Laravel framework o pacote Eloquent é o responsável por implementar o Model de acordo padrão de projeto ActiveRecord que, segundo Martin Fowler, consiste em objetos capazes de representar uma ou mais linha de uma tabela do banco de dados, encapsulando o acesso e adicionando lógica de domínio a esses dados.

Assim, cada Model da aplicação corresponde a todas as tabelas do banco de dados, fazendo de maneira simples o mapeamento objeto-relacional (ORM – Object-Relational Mapping).

A camada model abstrai o banco de dados mediante uma lógica de mapeamento Objeto-Relacional.

Mecanismos de inferência do Eloquent

O Eloquent simplifica o acesso ao banco de dados usando padrões e convenções de nomes, considerando a língua inglesa;

Os campos da tabela do banco de dados possuem os mesmos nomes dos atributos de dados do model correspondente.

Por exemplo, se um model possui o nome Product (primeira letra sempre maiúscula), a tabela correspondente no banco de dadosw será products (todas as letras minúsculas).

Sobre as convenções de nomes de tabelas: Caso você queira usar os nomes das tabelas e models em português, será necessário fazer adaptações no código.

O Eloquent assume que todas as tabelas possuem uma chave primária chama com o nome id inicialmente, todos os campos id são do tipo auto-incremento e chave primária.

As chaves estrangeiras seguem o seguinte padrão: nome da tabela relacionada, underscore e id. Por exemplo: imagine uma tabela products que possui um relacionamento 1:N com a tabela category. Nesse caso, a tabela products terá um campo chamado category_id que será a chave estrangeira apontando para a tabela category, campo id.

Por padrão, o Eloquent cria dois campos auxiliares em todas as tabelas: created_ate updated_at do tipo timestamp, para armazenar informações de alterações do registro.

Migrations

Agora que conhecemos o básico do comportamento do Eloquent, vamos falar sobre as migrations.

As migrations são classes que definem a estrutura do banco de dados na própria aplicação, ou seja, você cria e faz a manutenção do seu banco de dados sem usar nenhum comando SQL.

Segundo a documentação do Laravel, as migrations são usadas como controle de versão do banco de dados, pois permitem que a equipe modifique o banco de dados de maneira incremental, mantendo sempre a versão mais atualizada.

Para cada tabela temos uma migration. Cada migration possui uma lógica capaz de criar, modificar e destruir uma tabela do banco de dados.

Apesar de não ser obrigatório o uso de migrations, é altamente recomendável pois elas simplificam as operações de banco de dados e dão mais produtividade aos desenvolvedores. Assim, é recomendável criar um model e associá-lo a uma migration.

Hands on!

Vamos criar um novo projeto Laravel e fazer um laboratório prático com o Eloquent.

Caso o Laravel não esteja devidamente instalado e configurado no seu computador, clique aqui. Também é necessária a instalação de um banco de dados relacional.

Criando e inicializando um novo projeto Laravel

Para criar um novo projeto Laravel, abra o terminal e digite um dos comandos a seguir.

laravel new products
#ou
composer create-project laravel/laravel products

Depois que o projeto for criado, precisamos acessar a pasta dele e inicializar o servidor de desenvolvimento. Veja os seguintes comandos:

#acessar a pasta do projeto
CD products

#inicializar o projeto
php artisan serve

Após isso, um servidor será inicializado no IP 127.0.0.1, porta 8000. Essa é nossa aplicação executando localmente.

Aplicação Laravel inicializada com sucesso.
Página inicial do projeto Laravel.

Criando models e migrations

Usando o terminal (CMD ou Powershell), vá até a pasta do projeto e digite o comando:

php artisan make:model Product -m
Saída do comando de criação de model e migration.

O parâmetro -m indica que será criada uma migration para a classe model criada;

Caso desejar criar a migration separadamente, basta usar:

php artisan migrate:make create_products_table

Observe que o nome da migration inicia com o prefixo create_ e termina com o sufixo _table, sendo entre prefixo e sufixo, o nome da tabela. Sim, isso é uma convenção do Laravel, mas pode ser personalizado.

ATENÇÃO!

A partir da versão 8.x, os models ficam armazenados na pasta /app/Models (na versão 7.x fica apenas em app). Por padrão, já vem um model de nome User. Pode excluí-la, pois não vamos usá-la nesse exemplo;

As migrations ficam armazenadas na pasta app/database/migrations e, antes do prefixo create_, possuem outro prefixo que determina o seu timestamp. Isso é importante porque as migrations devem ser criadas de modo que respeitem a sequência de criação das tabelas do banco de dados e seus respectivos relacionamentos.

Por padrão, o Laravel define três migrations: create_users_table , create_failed_jobs e create_password_resets. Você pode excluí-las para manter nosso código mais limpo.

Compreendendo o código da model

Abra a pasta app/Models e abra o arquivo Product.php. Vejamos o código:

<?php

//namespace of model
namespace App\Models;

//using Eloquent class to abstract the database
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

//model always extends Model from Eloquent
class Product extends Model
{
    //use a trait to use factory (fake data)
    use HasFactory;
}

A classe Model criada (Product) é extremamente limpa, entretanto precisamos entender alguns pontos importantes:

  • Ela usa duas classes do Eloquent:
    • HasFactory: permite a geração de dados fake para teste;
    • Model: classe base do Eloquent, que abstrai o banco de dados;
  • A classe Product herda a classe Model do Eloquent e usa um trait, também chamado de herança horizontal, pois injeta um código inteiro dentro de uma classe. Neste caso, ele permite a utilização de Factories (fábricas) que geram dados falsos para teste.

E é somente isso que a model precisa ter para “conversar” com o banco de dados. Duvida? Já vamos entender como isso é possível. Mas, primeiro, vamos entender o código da migration que foi criada.

Compreendendo o código da migration

Abra o arquivo da migration, localizado em database/migrations. Note que ela tem um prefixo que é um timestamp, ou seja, com a data e a hora em que ela foi criada. Vejamos o código:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('products', function (Blueprint $table) {
            //table structure must be defined here!
            $table->id();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('products');
    }
};

Note que a declaração da classe Migration possui a palavra return. Isso significa que ela poderá ser usada no console Artisan, ou seja, ela irá responder a um comando do CLI (command-line interface) do PHP.

A Migration criada possui dois métodos: up() e down();

Como o nome sugere, o método up() possui o código que define a estrutura da tabela; o método down() possui o código que faz o contrário, ou seja, destrói a tabela.

O método estático Schema::create(…) recebe como parâmetro o nome da tabela e uma função anônima que recebe um objeto Blueprint chamado table. Esse objeto Blueprint é o responsável por executar comandos de DDL (Data Definition Language) da linguagem SQL (Structured Query Language), ou seja, define a estrutura das tabelas.

A medida que o projeto avança, é possível criar migrations para cada alteração, sempre nessa lógica: o método up faz alterações e o método down desfaz essas alterações.

Vamos definir a migration imaginando uma tabela products, segundo o código comentado a seguir.

    public function up()
    {
        Schema::create('products', function (Blueprint $table) {
            //unique id - primary key included
            $table->id();
            //name - string with lenght 50 chars
            $table->string('name', 50);
            //value - decimal - 9 places, with 2 decimals
            $table->decimal('value', 9, 2);
            //timestamps to monitoring data 
            $table->timestamps();
        });
    }

Criando o banco de dados

Agora vamos criar o banco de dados e conectar a aplicação a ele. Neste exemplo, vamos usar o banco de dados MySQL/MariaDB.

Inicie o serviço do MySQL, abra o terminal e digite o seguinte comando e entre com a senha. Caso não tenha senha, simplesmente digite <enter> quando ela for requisitada.

mysql -u root -p

Estando conectado ao MySQL/MariaDB, podemos executar comandos nativos do banco de dados. Para criar o banco de dados, digite o seguinte comando. Note que products é o nome do banco de dados.

create database products;

Uma vez que o Banco de Dados foi criado, é necessário selecioná-lo para gerenciá-lo. Para isso, use o comando:

use products;

Agora, vamos configurar a conexão com o banco de dados.

Conectando a aplicação ao banco de dados

No Laravel framework, a conexão com o banco de dados é feita no arquivo .env, que fica na raiz do projeto.

Abra o referido arquivo e edite as seguintes configurações:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=products
DB_USERNAME=root
DB_PASSWORD=password

Caso o banco de dados usado seja o PostgreSQL, em DB_CONNECTION coloque o valor pgsql.

Executando as migrations

Uma vez que as migrations foram definidas, precisamos executar o comando para que as tabelas sejam devidamente criadas no banco de dados. O comando a seguir faz exatamente isso:

php artisan migrate
Saída do comando php artisan migrate mostrando que as migrations foram executadas.

Agora que as migrations foram executadas, vamos verificar o banco de dados e notar que as tabelas foram criadas. O comando show tables mostra uma série de tabelas, inclusive products, que nós definimos.

O comando show tables mostra as tabelas do banco de dados.

A tabela migrations é para o Laravel controlar a execução das migrations. As demais tabelas são padrão do framework. Também podemos usar os comandos desc e show para mostrar os detalhes de uma tabela. Veja:

Descrevendo a estrutura da tabela products.
Comando show create table products; – mostra o script DDL para a criação da tabela

Outros comandos úteis para as migrations:

  • php artisan migrate:status 👉 mostra quais migrations foram executadas
  • php artisan migrate:reset 👉 executa os métodos down() de todos as migrations – zera o banco de dados;
  • php artisan migrate:refresh 👉 recria o banco de dados – down() e depois up();
  • php artisan migrate:fresh 👉 não chama o método down(): dropa as tabelas diretamente no banco de dados e cria tudo novamente

Testando o banco de dados com o Tinker

O Tinker, um utilitário REPL (read-eval print loop) que permite interagir com toda a aplicação mediante uma CLI (command line interface).

É possível declara variáveis, criar funções, instanciar objetos, enfim, todas as classes da aplicação podem ser usadas diretamente na interface CLI agilizando os testes iniciais.

Para acessar o Tinker, digite o seguinte comando no terminal: php artisan tinker

Conectando ao Tinker.

O código a seguir mostra a instanciação de um objeto product, a atribuição dos dados e a execução do método save, que persiste o dado no banco de dados. O retorno desse método é true quando o dado é persistido com sucesso. Veja:

Persistindo na base de dados.

É importante destacar que, segundo os mecanismos de inferência do Eloquent, os objetos instanciados podem considerar como atributos os mesmos campos da tabela.

Após a persistência de mais dois ou três registros, podemos recuperá-los usando o método estático Product::all() . Veja:

Listando registros

Note que os objetos retornados estão em formato JSON (Javascript Object Notation). Isso é uma das vantagens do Eloquent, pois o formato JSON é mais simples para manipular dados.

O método estático Product::find(id) retorna um objeto mediante o id. Uma vez retornado, ele pode ser atualizado ou excluído. Veja:

Retornando o produto cujo id é 2.
Atualizando o registro retornado.
Excluindo um registro.

Conclusão

Neste artigo aprendemos como conectar a aplicação Laravel ao banco de dados, como usar as migrations para criar a estrutura do banco e, finalmente, realizar operações CRUD usando o Eloquent. Também conhecemos o Tinker, que pode ser usado para testar a aplicação via CLI.

No próximo post vamos criar um CRUD completo segundo o padrão arquitetural MVC, unindo tudo que foi mostrado até aqui.

Até lá! 👊😎

Jorge Luís Gregório

Jorge Luís Gregório

Professor e entusiasta de tecnologia, estudioso da cultura NERD e fã de quadrinhos, animes e games. Mais um pai de menino, casado com a mulher mais linda da galáxia e cristão convicto. Gosto de ler ficção científica e discutir tecnologia, filmes, seriados, teologia, filosofia e política. Quer falar sobre esses e diversos outros assuntos? Venha comigo!