Eloquent
Eloquent é o ORM do Laravel. Permite consultar e atualizar registos da base de dados através de models, sem escrever SQL manual para todas as operações.
Eu prefiro usar models, relationships e query scopes antes de recorrer a raw queries. Na maioria dos casos, tornam a intenção mais clara e mantêm o código próximo das convenções do Laravel.
Queries Base
Começa queries com Model::query() quando estás a construir uma chain.
Post::query()
->where('is_featured', true)
->latest()
->get();Isto torna a query explícita e fácil de expandir.
Usa first() quando esperas um model ou null:
$post = Post::query()
->where('slug', $slug)
->first();Usa firstOrFail() quando não encontrar o model deve devolver um 404:
$post = Post::query()
->where('slug', $slug)
->firstOrFail();Selecionar Colunas
Seleciona apenas as colunas necessárias quando estás a devolver listas.
Post::query()
->select('id', 'title', 'slug', 'published_at')
->latest('published_at')
->get();Isto mantém a query e a resposta mais pequenas, especialmente em tabelas com campos de texto grandes ou colunas JSON.
Relationships
Usa relationships em vez de juntar dados manualmente no código da aplicação.
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function comments(): HasMany
{
return $this->hasMany(Comment::class);
}Post::query()
->with('user')
->latest()
->get();O nome da relationship deve ler-se naturalmente na query. Um post pertence a um user, e um post tem muitos comments.
Eager Loading
Usa with() quando sabes que a view ou resposta da API vai precisar de dados relacionados.
Post::query()
->with(['user', 'comments'])
->latest()
->get();Isto ajuda a evitar N+1 queries.
Também podes limitar as colunas da relationship:
Post::query()
->with('user:id,name')
->select('id', 'user_id', 'title', 'slug')
->latest()
->get();Quando limitas colunas, lembra-te de incluir a foreign key. Neste exemplo, user_id é necessário para o Eloquent ligar cada post ao seu user.
Filtrar Por Relationships
Usa whereHas() quando a query depende de uma relationship.
Post::query()
->whereHas('comments', function ($query): void {
$query->where('is_approved', true);
})
->latest()
->get();Usa withWhereHas() quando queres filtrar por uma relationship e fazer eager load da mesma relationship já filtrada.
Post::query()
->withWhereHas('comments', function ($query): void {
$query->where('is_approved', true);
})
->latest()
->get();Scopes
Usa scopes quando uma condição representa uma regra reutilizável.
use Illuminate\Database\Eloquent\Builder;
public function scopePublished(Builder $query): void
{
$query->whereNotNull('published_at');
}Post::query()
->published()
->latest('published_at')
->get();Scopes são úteis quando fazem a query ler-se como o domínio. Evita criar um scope para cada pequena condição se só for usado uma vez.
Queries Condicionais
Usa when() quando um filtro é opcional.
Post::query()
->when($request->string('search')->isNotEmpty(), function ($query) use ($request): void {
$query->where('title', 'like', '%' . $request->string('search') . '%');
})
->latest()
->paginate();Isto evita grandes blocos if à volta da query.
Paginação
Usa paginação para listas que podem crescer.
$posts = Post::query()
->select('id', 'title', 'slug', 'published_at')
->latest('published_at')
->paginate(15);Com Inertia, devolve o resultado paginado como prop:
return Inertia::render('posts/index', [
'posts' => $posts,
]);Criar Registos
Usa dados validados de um Form Request ao criar registos.
$post = Post::query()->create($request->validated());O model deve definir os campos mass assignable com #[Fillable] ou $fillable, dependendo da convenção do projeto.
Atualizar Registos
Para updates simples, atualiza diretamente o model.
$post->update($request->validated());Se o update tem vários passos, side effects, uploads de ficheiros ou notificações, movo esse fluxo para uma Action.
Apagar Registos
Para deletes simples, chama delete() no model.
$post->delete();Quando apagar exige trabalho extra, como remover ficheiros enviados ou detach de relationships, prefiro colocar isso numa Action.
Transactions
Usa uma transaction quando várias alterações na base de dados devem funcionar ou falhar juntas.
use Illuminate\Support\Facades\DB;
DB::transaction(function () use ($data): void {
$post = Post::query()->create($data);
$post->tags()->attach($data['tag_ids']);
});Se o post for criado mas as tags falharem, a transaction faz rollback de tudo.
Debug De Queries
Usa toSql() quando queres inspecionar o SQL gerado.
$sql = Post::query()
->where('is_featured', true)
->toSql();Usa dd() com cuidado enquanto estás a fazer debug localmente:
Post::query()
->where('is_featured', true)
->dd();Não deixes helpers de debug de queries em código commitado.
Notas
- Prefere
Model::query()para query chains legíveis. - Usa relationships antes de juntar dados manualmente.
- Usa eager loading para evitar N+1 queries.
- Prefere scopes quando a query representa uma regra reutilizável.
- Mantém fluxos grandes em Actions em vez de os esconder dentro de query chains.