Introdução ao Eloquent ORM
O Eloquent é o Object-Relational Mapping (ORM) padrão do Laravel, permitindo interagir com bancos de dados usando orientação a objetos. Em vez de escrever SQL puro, você trabalha com modelos PHP que representam suas tabelas. Esta abordagem torna o código mais legível, seguro contra SQL injection e muito mais produtivo. Nesta aula, você aprenderá os pilares fundamentais: criar modelos, definir relacionamentos e implementar scopes para consultas reutilizáveis.
Models: Fundação do Eloquent
Criando seu primeiro Model
Um Model no Eloquent é uma classe PHP que estende Model e representa uma tabela do banco de dados. Para criar um model, use o artisan:
php artisan make:model Post
Isto gera um arquivo app/Models/Post.php. O Laravel assume que a tabela correspondente é posts (plural, em snake_case). Se sua tabela tiver outro nome, defina a propriedade $table:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $table = 'meus_posts'; // nome customizado
protected $fillable = ['title', 'content', 'author_id'];
}
A propriedade $fillable define quais atributos podem ser atribuídos em massa usando create() ou update(), protegendo contra atribuição em massa acidental. Use $visible e $hidden para controlar quais atributos aparecem em JSON:
protected $hidden = ['password', 'remember_token'];
protected $visible = ['id', 'title', 'content'];
Operações CRUD básicas
Com o model definido, as operações são intuitivas:
// CREATE
$post = Post::create([
'title' => 'Meu primeiro post',
'content' => 'Conteúdo aqui',
'author_id' => 1
]);
// READ
$post = Post::find(1);
$posts = Post::all();
$posts = Post::where('author_id', 1)->get();
// UPDATE
$post->update(['title' => 'Título atualizado']);
// DELETE
$post->delete();
Post::destroy([1, 2, 3]); // deleta múltiplos
Relacionamentos: Conectando Models
Um para Muitos (One to Many)
O relacionamento mais comum. Um autor tem muitos posts. Defina no model Author:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Author extends Model
{
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
}
E no model Post, defina o inverso:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Post extends Model
{
public function author(): BelongsTo
{
return $this->belongsTo(Author::class);
}
}
Agora você usa os relacionamentos assim:
$author = Author::find(1);
$posts = $author->posts; // carrega todos os posts do autor
$post = Post::find(1);
$author = $post->author; // carrega o autor do post
Muitos para Muitos (Many to Many)
Um post pertence a várias categorias e uma categoria tem vários posts. Crie uma tabela pivot category_post:
Schema::create('category_post', function (Blueprint $table) {
$table->id();
$table->foreignId('post_id')->constrained()->cascadeOnDelete();
$table->foreignId('category_id')->constrained()->cascadeOnDelete();
$table->timestamps();
});
Defina no model Post:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Post extends Model
{
public function categories(): BelongsToMany
{
return $this->belongsToMany(Category::class);
}
}
E no model Category:
public function posts(): BelongsToMany
{
return $this->belongsToMany(Post::class);
}
Use assim:
$post = Post::find(1);
$post->categories; // todas as categorias do post
$post->categories()->attach(2); // associa categoria id 2
$post->categories()->detach(2); // desassocia
$post->categories()->sync([1, 3]); // sincroniza (remove outras)
Scopes: Consultas Reutilizáveis
Local Scopes
Scopes permitem encapsular lógica de filtro em métodos reutilizáveis. No model Post, crie um scope prefixado com scope:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
class Post extends Model
{
public function scopePublished(Builder $query): Builder
{
return $query->where('published', true);
}
public function scopeByAuthor(Builder $query, int $authorId): Builder
{
return $query->where('author_id', $authorId);
}
public function scopeRecent(Builder $query): Builder
{
return $query->orderBy('created_at', 'desc');
}
}
Use os scopes como métodos sem o prefixo scope:
// Cada scope encadeia automaticamente
$posts = Post::published()
->byAuthor(1)
->recent()
->get();
// Equivalente a:
// SELECT * FROM posts WHERE published = 1 AND author_id = 1
// ORDER BY created_at DESC
Global Scopes
Aplique filtros automaticamente a todas as consultas de um model. Útil para soft deletes ou multi-tenant:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Scope;
class PublishedScope implements Scope
{
public function apply(Builder $builder, Model $model): void
{
$builder->where('published', true);
}
}
Registre no model:
protected static function booted(): void
{
static::addGlobalScope(new PublishedScope());
}
Agora Post::all() retorna apenas posts publicados automaticamente. Para ignorar: Post::withoutGlobalScopes()->get().
Conclusão
Você aprendeu os três pilares do Eloquent: Models abstraem suas tabelas em classes PHP com operações intuitivas; Relacionamentos conectam models de forma elegante (one-to-many, many-to-many); Scopes reutilizam lógica de filtro, mantendo controllers limpos. Domine estes conceitos e seu código Laravel será significativamente mais organizado e eficiente.