Eloquent no Laravel 8: as principais funcionalidades do ORM

Eloquent no Laravel 8: as principais funcionalidades do ORM
O Eloquent, que vem incluído no conhecido framework PHP Laravel, oferece uma forma elegante e muito eficaz de comunicar com a base de dados. Os sites são cada vez mais complexos por causa das personalizações que se acumulam, e os programadores acabam com bases de dados igualmente complexas nas mãos. O Laravel Eloquent simplifica esse trabalho: deixa-te escrever código bem formatado, fácil de ler, duradouro e bem documentado. Com tantas funcionalidades à mão, é uma das razões do sucesso do Laravel.Neste artigo passamos em revista algumas das funcionalidades mais importantes do Eloquent ORM.

O que é o Eloquent ORM?

O Eloquent ORM é distribuído com o framework Laravel para trabalhares com a base de dados de forma simples e sem complicações. Algumas das funcionalidades que lhe deram fama são o soft delete, os timestamps, a implementação de Active Record, a gestão de várias bases de dados, o eager loading, os observers de modelo, os eventos de modelo e muitas outras. As relações do Eloquent são simplesmente métodos das classes de modelo. Definidas como métodos, tornam-se query builders poderosos: podes encadear chamadas e construir consultas muito expressivas.

Como funciona o Eloquent ORM?

O Eloquent ORM é conhecido pela sua implementação de Active Record para trabalhar com bases de dados. O Active Record é um padrão de arquitetura em que cada modelo da arquitetura MVC corresponde a uma tabela da base de dados. Com o Eloquent, crias facilmente dados relacionados na tua base de dados e trabalhas com eles através de um modelo orientado a objetos. Escrever consultas SQL à mão é fastidioso e consome muito tempo. O Laravel Eloquent deixa-te realizar as operações habituais sem longas instruções SQL. Os modelos tornaram triviais a inserção, a atualização, a eliminação e a sincronização entre várias bases de dados. Basta definires as tabelas e a relação entre elas, e está feito.

Começar com o Eloquent

O Laravel traz uma interface de linha de comandos integrada, a consola Artisan. Construída sobre o componente Console do Symfony, dá-te uma forma cómoda de trabalhar a partir do terminal durante a fase de desenvolvimento.

Antes de avançares neste artigo, configura a ligação à base de dados no ficheiro config/database.php.

Antes de começares a usar um modelo Eloquent, verifica se tens o Laravel instalado. Se não tiveres, podes descarregá-lo em getcomposer.org

Para veres a lista de comandos disponíveis no Artisan, escreve o seguinte:

bash
php artisan list

Todos os comandos aparecem então no ecrã com uma descrição curta. Se precisares de ajuda sobre um deles, escreve o comando precedido de «help». Por exemplo:

bash
php artisan help migrate

Criar modelos Eloquent

Antes de mais, precisas de um modelo para a tua tabela. Os modelos ajudam-te nos seeders, nas factories e no resto. É o modelo que comunica com a base de dados: permite-te consultar as tuas tabelas e povoá-las com dados. Os modelos são normalmente guardados em App\Models apenas por uma questão de código bem documentado. Também preferimos essa convenção, mas a escolha é inteiramente tua, a única exigência é que a classe seja carregada automaticamente segundo o teu ficheiro composer.json. Todos os modelos Eloquent estendem a classe Illuminate\Database\Eloquent\Model. O comando de base para criar modelos é o `make:model` do Artisan:

bash
php artisan make: model Student

A sintaxe de base para definir um modelo é:

php
class User extends Model {}

A migração da base de dados também pode ser gerada ao mesmo tempo que o modelo, bastando acrescentar `-m` ou `-migration` ao comando anterior.

bash
php artisan make:model Student--migration
php artisan make:model Flight -m

Seeders, factories, controladores e vários outros tipos de classes podem ser gerados passando as opções certas ao comando Artisan `make:model`. Aqui ficam alguns exemplos:

bash
php artisan make:model Flight --factory
php artisan make:model Flight -f

php artisan make:model Flight --seed
php artisan make:model Flight -s

php artisan make:model Flight --controller
php artisan make:model Flight -c

Estas opções também podem ser combinadas para criar várias classes de uma só vez.

bash
php artisan make:model Flight -mfsc

Algumas convenções de modelo a ter em mente:

  • Nome da tabela: por convenção, os nomes de tabela escrevem-se em minúsculas e no plural, seja qual for a base de dados. Por exemplo, se o modelo se chama Student então a tabela deve chamar-se students. Se o nome do modelo tiver várias palavras, separa-as com underscores.
  • Chave primária: o Eloquent parte do princípio de que a chave primária é o atributo id. Podes substituir esse comportamento com `$primaryKey`.
  • Timestamps: por omissão, `created_at` e `updated_at` são geridos automaticamente pelo Eloquent. Se preferires tratar deles à mão, põe `$timestamp` a false. Para personalizares o formato de data e hora, usa a propriedade `$dateFormat` do teu modelo.

Atualizar e apagar registos

Atualizar

Para atualizares um modelo, vai buscá-lo, altera o atributo que queres mudar e chama o método save. A coluna `updated_at` é atualizada automaticamente, por isso não precisas de lhe tocar.

php
$student = Student::find(1);

$student->email = ‘xyz@example.com';

$student>save();

As atualizações em massa também podem ser feitas sobre todos os modelos que correspondem a uma dada consulta.

Apagar um modelo existente

Para apagares um modelo, basta chamar o método delete:

php
$student = Student::find(1);

$student>delete();

Apagar pela chave:

php
Student::destroy(1);

Student::destroy([1, 2, 3]);

Student::destroy(1, 2, 3);

Também podes apagar com base numa consulta.

php
$affectedRows = Student::where('votes', '>', 100)->delete();

Modelos relacionados

Qualquer base de dados pode conter modelos relacionados. Quando dois ou mais modelos dependem uns dos outros para os seus valores, chamam-se modelos relacionados. Por exemplo, para acrescentares um novo comentário a um artigo, em vez de preencheres o post_id à mão, podes guardar o comentário diretamente a partir do seu modelo pai

php
$comment = new Comment(['message' => 'A new comment.']);

$post = Post::find(1);

$comment = $post->comments()->save($comment);

Associar modelos

Estes modelos também podem ser atualizados com o método associate, que define uma chave estrangeira no modelo. Podes ainda associar modelos através de várias relações.

Eventos de modelo

Sempre que queres intervir nas etapas do ciclo de vida de um modelo, como a gravação, a atualização ou a eliminação, é disparado um evento: é o evento de modelo. Os eventos disponíveis são saving, saved, deleting, deleted, updating, updated, restoring e restored. Por exemplo, inserir um registo novo dispara o evento creating/created, enquanto um registo que já existe dispara o evento updating/updated.

Cancelar a gravação a partir de um evento

Se o evento devolver false, a ação é cancelada. Serve qualquer evento: deleting, updating, creating, e por aí adiante.

php
Student::creating(function($student)
{
    if ( ! $student>isValid()) return false;
});

Como registar listeners de eventos

Como em qualquer linguagem, um evento precisa de um service provider para ser registado, e com os listeners passa-se o mesmo. O Laravel traz o EventServiceProvider que serve de sítio para registares os teus bindings de eventos de modelo.

Por exemplo:

php
public function boot(DispatcherContract $events)
{
    parent::boot($events);

Student::creating(function($student)
    {
        //
    });
}

Observers de modelo

Os observers de modelo ajudam-te a tratar os eventos de modelo. Uma classe de observer pode ter um método por cada evento de modelo.

php
class StudentObserver {

public function saving($model)
    {
        //
    }

public function saved($model)
    {
        //
    }

}

Outra forma de registar um observer é através do método observe

php
User::observe(new UserObserver);

Gerar URLs de modelo

Os URLs de modelo dão-te o URL de um registo único, bastando passar o modelo ao helper route ou action. Quando um modelo é passado a route ou a action, a sua chave primária é inserida no URI.

php
Route::get('student/{student}', 'StudentController@show');

action('StudentController@show', [$student]);

Aqui, o id do estudante é inserido no URL. Se quiseres usar outra propriedade no URL gerado, tens de substituir o método getRouteKey no teu modelo.

php
public function getRouteKey()
{
    return $this->slug;
}

Mais sobre as funcionalidades do Laravel Eloquent

Converter em arrays e JSON

Quando constróis uma API, a resposta é quase sempre em JSON, o que te obriga a transformar os teus modelos e as suas relações em JSON ou em arrays. O Laravel Eloquent também responde a essa necessidade. Para converteres um modelo e as suas relações num array, usa o método toArray().

php
$student = Student::with('roles')->first();

return $student->toArray();

Para converteres um modelo em JSON, podes usar o método seguinte:

php
return Student::find(1)->toJson();

Vejamos agora como devolver um modelo a partir de uma rota. Sempre que um modelo é convertido em string, passa a JSON, por isso podes devolver objetos Eloquent diretamente a partir das tuas rotas.

php
Route::get('student', function()
{
    return Student::all();
});

Alguns valores protegidos, como `personal_id` ou a palavra-passe, devem ficar escondidos. Para isso, acrescenta `$hidden` ao teu modelo,

Casting de atributos

Se queres mudar o tipo de dados de um atributo, uma opção é escrever um mutator para cada um deles, o que demora tempo e convida a erros. A outra opção é fazer o cast do atributo em questão: acrescenta-o à propriedade casts do teu modelo. Os outros tipos de cast aceites são integer, float, double, real, object, string, array.

Aqui fica um exemplo.

php
protected $casts = [
    'is_student' => 'boolean',
];

Neste exemplo, mesmo que is_student esteja guardado com outro tipo de dados, ao lê-lo obténs sempre um boolean.

O cast em array é muito prático quando trabalhas com uma coluna que guarda JSON serializado. JSON serializado significa apenas um objeto codificado numa string. Se uma das tuas colunas contém JSON serializado, o cast em array converte-o automaticamente num array PHP assim que o lês a partir do teu modelo Eloquent.

php
protected $casts = [
    'options' => 'array',
];

Mutators de data

O Carbon é uma extensão internacional do DateTime do PHP. O Eloquent converte created_at e updated_at em instâncias de Carbon, que estendem a classe DateTime do PHP e acrescentam vários métodos úteis. Personalizar isto é fácil se não quiseres a mutação automática: basta substituíres o método getDates na tua classe. Para desativares completamente a mutação de datas, devolve um array vazio no método `getDates` desta classe. Aqui fica um exemplo:

php
public function getDates()
{
    return ['created_at'];
}

Quando uma coluna é tratada como data, tens quatro possibilidades para o seu valor: um timestamp UNIX, uma string de data (Y-m-d), uma data-hora ou uma instância de DateTime/Carbon.

Accessors e mutators

Tal como ler e escrever valores em qualquer linguagem, os accessors e os mutators permitem-te formatar os atributos Eloquent antes de os ler ou de os escrever nas instâncias do modelo. A diferença entre os dois é que os accessors servem para ler os dados, enquanto os mutators são responsáveis por os alterar.

Para definires um accessor, declara `getFooAttribute` no teu modelo, o nome do método tem de estar em camel case, quer o nome da coluna esteja em minúsculas ou não.

php
class User extends Model {

public function getFirstNameAttribute($value)
    {
        return ucfirst($value);
    }

}

Um mutator define-se da mesma forma: usa `setFooAttribute` e sim, o camel case também se aplica aqui.

php
class User extends Model {

public function setFirstNameAttribute($value)
    {
        $this->attributes['first_name'] = strtolower($value);
    }

}

Soft deletes

Um soft delete não apaga a linha da base de dados, escreve um timestamp à parte. Uma coluna `deleted_at` é preenchida no registo correspondente. Podes fazer soft delete no teu modelo aplicando-lhe o trait SoftDeletes.

php
use Illuminate\Database\Eloquent\SoftDeletes;

class User extends Model {

use SoftDeletes;

protected $dates = ['deleted_at'];

}

softDeletes() serve para acrescentar a coluna deleted_at na migração. Uma migração não é mais do que gerir a tua base de dados em PHP em vez de SQL.

php
$table->softDeletes();

Nalguns casos vais querer que as linhas em soft delete apareçam nos resultados de uma consulta. Para isso, usa o withTrashed() na consulta.

Para mostrares apenas os modelos em soft delete nos resultados, usa o método onlyTrashed() na consulta.

php
$student = Student::onlyTrashed()->where('account_id', 1)->get();

Depois de todas estas operações, se quiseres repor os modelos em soft delete no ativo, chama o método restore no modelo.

php
$student->restore();

restore() também pode ser usado diretamente na consulta.

php
Student::withTrashed()->where('account_id', 1)->restore();

Agora, depois de um soft delete, se quiseres apagar o modelo da base de dados de vez, usa o forceDelete() no modelo.

php
$student->posts()->forceDelete();

Para verificares se um modelo foi apagado ou não, podes usar o método trashed().

php
if ($student->trashed())
{
    //Todo
}

Conclusão

O Laravel é um dos frameworks PHP mais conhecidos, e o Laravel Eloquent dá-te uma forma muito simples de comunicar com as tuas bases de dados. Neste artigo cobrimos algumas das funcionalidades importantes do Eloquent. Há muitas mais, e podes lê-las aqui. Segue a ligação e descobre tudo o que o Laravel Eloquent sabe fazer.


LaravelPHP

Damien Flandrin Programador web desde 2010, criador da Gekkode e do Email Impact. Cada artigo é testado num projeto real antes de ser publicado. Contacto
Newsletter

Os novos testes, tutoriais e projetos, por e-mail.

Testes reproduzíveis, código versionado, resultados datados. Nunca spam.