<h2>Introdução ao Eloquent ORM</h2>
<p>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.</p>
<h2>Models: Fundação do Eloquent</h2>
<h3>Criando seu primeiro Model</h3>
<p>Um Model no Eloquent é uma classe PHP que estende <code>Model</code> e representa uma tabela do banco de dados. Para criar um model, use o artisan:</p>
<pre><code class="language-bash">php artisan make:model Post</code></pre>
<p>Isto gera um arquivo <code>app/Models/Post.php</code>. O Laravel assume que a tabela correspondente é <code>posts</code> (plural, em snake_case). Se sua tabela tiver outro nome, defina a propriedade <code>$table</code>:</p>
<pre><code class="language-php"><?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'];
}</code></pre>
<p>A propriedade <code>$fillable</code> define quais atributos podem ser atribuídos em massa usando <code>create()</code> ou <code>update()</code>, protegendo contra atribuição em massa acidental. Use <code>$visible</code> e <code>$hidden</code> para controlar quais atributos aparecem em JSON:</p>
<pre><code class="language-php">protected $hidden = ['password', 'remember_token'];
protected $visible = ['id', 'title', 'content'];</code></pre>
<h3>Operações CRUD básicas</h3>
<p>Com o model definido, as operações são intuitivas:</p>
<pre><code class="language-php">// 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</code></pre>
<h2>Relacionamentos: Conectando Models</h2>
<h3>Um para Muitos (One to Many)</h3>
<p>O relacionamento mais comum. Um autor tem muitos posts. Defina no model <code>Author</code>:</p>
<pre><code class="language-php"><?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);
}
}</code></pre>
<p>E no model <code>Post</code>, defina o inverso:</p>
<pre><code class="language-php"><?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);
}
}</code></pre>
<p>Agora você usa os relacionamentos assim:</p>
<pre><code class="language-php">$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</code></pre>
<h3>Muitos para Muitos (Many to Many)</h3>
<p>Um post pertence a várias categorias e uma categoria tem vários posts. Crie uma tabela pivot <code>category_post</code>:</p>
<pre><code class="language-php">Schema::create('category_post', function (Blueprint $table) {
$table->id();
$table->foreignId('post_id')->constrained()->cascadeOnDelete();
$table->foreignId('category_id')->constrained()->cascadeOnDelete();
$table->timestamps();
});</code></pre>
<p>Defina no model <code>Post</code>:</p>
<pre><code class="language-php"><?php
namespace App\Models;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Post extends Model
{
public function categories(): BelongsToMany
{
return $this->belongsToMany(Category::class);
}
}</code></pre>
<p>E no model <code>Category</code>:</p>
<pre><code class="language-php">public function posts(): BelongsToMany
{
return $this->belongsToMany(Post::class);
}</code></pre>
<p>Use assim:</p>
<pre><code class="language-php">$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)</code></pre>
<h2>Scopes: Consultas Reutilizáveis</h2>
<h3>Local Scopes</h3>
<p>Scopes permitem encapsular lógica de filtro em métodos reutilizáveis. No model <code>Post</code>, crie um scope prefixado com <code>scope</code>:</p>
<pre><code class="language-php"><?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');
}
}</code></pre>
<p>Use os scopes como métodos sem o prefixo <code>scope</code>:</p>
<pre><code class="language-php">// 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</code></pre>
<h3>Global Scopes</h3>
<p>Aplique filtros automaticamente a todas as consultas de um model. Útil para soft deletes ou multi-tenant:</p>
<pre><code class="language-php"><?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);
}
}</code></pre>
<p>Registre no model:</p>
<pre><code class="language-php">protected static function booted(): void
{
static::addGlobalScope(new PublishedScope());
}</code></pre>
<p>Agora <code>Post::all()</code> retorna apenas posts publicados automaticamente. Para ignorar: <code>Post::withoutGlobalScopes()->get()</code>.</p>
<h2>Conclusão</h2>
<p>Você aprendeu os três pilares do Eloquent: <strong>Models</strong> abstraem suas tabelas em classes PHP com operações intuitivas; <strong>Relacionamentos</strong> conectam models de forma elegante (one-to-many, many-to-many); <strong>Scopes</strong> reutilizam lógica de filtro, mantendo controllers limpos. Domine estes conceitos e seu código Laravel será significativamente mais organizado e eficiente.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://laravel.com/docs/eloquent" target="_blank" rel="noopener noreferrer">Documentação oficial Eloquent ORM</a></li>
<li><a href="https://laravel.com/docs/eloquent-relationships" target="_blank" rel="noopener noreferrer">Eloquent Relationships - Laravel Docs</a></li>
<li><a href="https://laravel.com/docs/eloquent#query-scopes" target="_blank" rel="noopener noreferrer">Query Scopes - Laravel Docs</a></li>
<li><a href="https://laravel.com/docs/eloquent#retrieving-single-models" target="_blank" rel="noopener noreferrer">Laravel Best Practices - Eloquent Patterns</a></li>
<li><a href="https://www.oreilly.com/library/view/laravel-up-and/9781491926421/" target="_blank" rel="noopener noreferrer">Livro: "Laravel Up and Running" - Matt Stauffer</a></li>
</ul>