> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Introductie tot Eloquent

> Uitleg over het bewerken van databasedata met Eloquent, de ORM van Laravel.

## Wat is Eloquent ORM?

Laravel bevat een object-relational mapper (ORM) genaamd Eloquent.
Eloquent maakt de interactie met de database eenvoudig en implementeert het **ActiveRecord-patroon**.

Met Eloquent maak je voor elke databasetabel een bijbehorende "model"-klasse.
Via het model kun je records ophalen, invoegen, bijwerken en verwijderen.

<Info>
  Configureer voordat je Eloquent gebruikt je databaseverbinding in `config/database.php`.
  Standaard worden de `DB_*`-instellingen uit het `.env`-bestand gebruikt.
</Info>

## Modellen maken

Genereer een nieuw model met het Artisan-commando `make:model`.

```shell theme={null}
php artisan make:model Post
```

Wil je tegelijk een migratie aanmaken, gebruik dan de optie `-m`.

```shell theme={null}
php artisan make:model Post -m
```

Modellen worden aangemaakt in de map `app/Models`.

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    // ...
}
```

## De relatie tussen modellen en tabellen

Eloquent leidt de tabelnaam automatisch af uit de klassennaam.
De tabelnaam is de klassennaam omgezet naar de meervoudsvorm in snake\_case.

| Modelnaam              | Tabelnaam                 |
| ---------------------- | ------------------------- |
| `Post`                 | `posts`                   |
| `User`                 | `users`                   |
| `AirTrafficController` | `air_traffic_controllers` |

Als de tabelnaam niet aan de naamgevingsconventie voldoet, kun je die expliciet opgeven met de `$table`-property op het model.

```php theme={null}
class Post extends Model
{
    protected $table = 'blog_posts';
}
```

### Timestamps

Eloquent beheert standaard automatisch de kolommen `created_at` en `updated_at`.
Als je in je migratie `$table->timestamps()` toevoegt, worden de waarden automatisch gezet bij het opslaan en bijwerken van het model.

Om het automatisch beheren van timestamps uit te schakelen, zet je `$timestamps` op `false`.

```php theme={null}
class Post extends Model
{
    public $timestamps = false;
}
```

## Bescherming tegen mass assignment

Wanneer je met Eloquent data in bulk opslaat, moet je de bescherming tegen mass assignment configureren.

### fillable

Met de `$fillable`-property geef je op welke kolommen toewijzing toestaan.

```php theme={null}
class Post extends Model
{
    protected $fillable = [
        'user_id',
        'title',
        'body',
        'published',
    ];
}
```

### guarded

Omgekeerd gebruik je `$guarded` om kolommen op te geven waarvoor toewijzing verboden is.

```php theme={null}
class Post extends Model
{
    // Alleen de primaire sleutel beschermen, al het andere toestaan
    protected $guarded = ['id'];
}
```

<Warning>
  Als je `$guarded` een lege array maakt, sta je toewijzing aan alle kolommen toe.
  Als je gebruikersinvoer rechtstreeks doorgeeft, bestaat het risico dat onbedoelde kolommen worden overschreven; we raden daarom aan de toegestane kolommen expliciet op te geven met `$fillable`.
</Warning>

## De uitvoeringsflow van een Eloquent-query

Zo verloopt intern de uitvoering van een query als `User::where()->get()`.

```mermaid theme={null}
flowchart LR
    A["User::where('active', true)"] --> B["Querybuilder opbouwen"]
    B --> C["->get() aanroepen"]
    C --> D["SQL genereren"]
    D --> E["Uitvoeren op de database"]
    E --> F["Resultaat omzetten naar Eloquent-modellen"]
    F --> G["Teruggeven als Collection"]
```

## Basis-CRUD-bewerkingen

### Records ophalen (Read)

Alle records ophalen:

```php theme={null}
use App\Models\Post;

$posts = Post::all();
```

Ophalen met voorwaarden:

```php theme={null}
// Posts ophalen waarvan published true is
$publishedPosts = Post::where('published', true)->get();

// Het eerste record ophalen
$post = Post::where('published', true)->first();

// Eén record ophalen op ID
$post = Post::find(1);

// Een 404-response teruggeven als het niet gevonden wordt
$post = Post::findOrFail(1);
```

### Records aanmaken (Create)

Met de `create`-methode voeg je één record in (de `$fillable`-configuratie is vereist).

```php theme={null}
$post = Post::create([
    'title' => 'Mijn eerste bericht',
    'body' => 'Laravel is een geweldig framework.',
    'published' => true,
]);
```

Je kunt ook een instantie maken en de waarden afzonderlijk toewijzen.

```php theme={null}
$post = new Post;
$post->title = 'Mijn eerste bericht';
$post->body = 'Laravel is een geweldig framework.';
$post->save();
```

### Records bijwerken (Update)

Haal het model op, wijzig de waarden en roep `save` aan om bij te werken.

```php theme={null}
$post = Post::find(1);
$post->title = 'Bijgewerkte titel';
$post->save();
```

Met de `update`-methode kun je meerdere kolommen tegelijk bijwerken.

```php theme={null}
Post::find(1)->update([
    'title' => 'Bijgewerkte titel',
    'published' => true,
]);
```

Je kunt ook meerdere records die aan een voorwaarde voldoen in één keer bijwerken.

```php theme={null}
Post::where('published', false)->update(['published' => true]);
```

### Een model herladen met een pessimistische lock

Om een model binnen een transactie opnieuw te laden en tegelijkertijd een pessimistische lock te verkrijgen, gebruik je de `refreshForUpdate`-methode. Het model wordt opnieuw geladen met een `FOR UPDATE`-lock.

```php theme={null}
use Illuminate\Support\Facades\DB;

DB::transaction(function () use ($post) {
    $post->refreshForUpdate();

    // Het gelockte model bijwerken...
});
```

### Records verwijderen (Delete)

Verwijder een record met de `delete`-methode.

```php theme={null}
$post = Post::find(1);
$post->delete();
```

Je kunt ook rechtstreeks verwijderen op ID.

```php theme={null}
Post::destroy(1);

// Meerdere ID's tegelijk verwijderen
Post::destroy([1, 2, 3]);
```

## Basisquerymethoden

| Methode                                      | Beschrijving                                              |
| -------------------------------------------- | --------------------------------------------------------- |
| `Post::all()`                                | Alle records ophalen                                      |
| `Post::find($id)`                            | Eén record ophalen op ID (`null` als niet gevonden)       |
| `Post::findOrFail($id)`                      | Eén record ophalen op ID (404 als niet gevonden)          |
| `Post::where('column', 'value')->get()`      | Records ophalen die aan een voorwaarde voldoen            |
| `Post::where('column', 'value')->first()`    | Het eerste record ophalen dat aan een voorwaarde voldoet  |
| `Post::where('column', 'value')->count()`    | Het aantal records ophalen dat aan een voorwaarde voldoet |
| `Post::orderBy('created_at', 'desc')->get()` | Ophalen met opgegeven sortering                           |
| `Post::latest()->get()`                      | Ophalen in aflopende volgorde van `created_at`            |
| `Post::limit(10)->get()`                     | Ophalen met beperkt aantal                                |

## Praktijkvoorbeeld: databewerking met het Post-model

Een voorbeeld van een controller die de met een migratie aangemaakte `posts`-tabel bewerkt.

```php theme={null}
<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;

class PostController extends Controller
{
    // Toon de lijst met posts
    public function index(): View
    {
        $posts = Post::where('published', true)
            ->latest()
            ->get();

        return view('posts.index', ['posts' => $posts]);
    }

    // Maak een post aan
    public function store(Request $request): RedirectResponse
    {
        $validated = $request->validate([
            'title' => ['required', 'string', 'max:255'],
            'body' => ['required', 'string'],
            'published' => ['boolean'],
        ]);

        Post::create([
            ...$validated,
            'user_id' => $request->user()->id,
        ]);

        return redirect('/posts');
    }

    // Werk een post bij
    public function update(Request $request, Post $post): RedirectResponse
    {
        $validated = $request->validate([
            'title' => ['required', 'string', 'max:255'],
            'body' => ['required', 'string'],
        ]);

        $post->update($validated);

        return redirect('/posts');
    }

    // Verwijder een post
    public function destroy(Post $post): RedirectResponse
    {
        $post->delete();

        return redirect('/posts');
    }
}
```

<Tip>
  Als je `Post $post` schrijft als methode-argument van je controller, haalt Laravel het model automatisch op uit de routeparameter (route model binding).
  Je hoeft dan niet zelf `Post::findOrFail($id)` te schrijven.
</Tip>

## De levenscyclus van model-events

Zo verloopt de stroom van events die worden afgevuurd wanneer je `save()` aanroept. Afhankelijk van of het om aanmaken of bijwerken gaat, worden verschillende events afgevuurd, maar `saving` en `saved` worden in beide gevallen afgevuurd.

```mermaid theme={null}
flowchart TD
    A["Nieuwe instantie aanmaken"] --> B{"save()"}
    B --> I["saving-event"]
    I -->|"Nieuw"| C["creating-event"]
    C --> D["INSERT uitvoeren"]
    D --> E["created-event"]
    I -->|"Bijwerken"| F["updating-event"]
    F --> G["UPDATE uitvoeren"]
    G --> H["updated-event"]
    E --> J["saved-event"]
    H --> J
```

## Volgende stappen

<Card title="Migraties" icon="table" href="/nl/migrations">
  Bekijk opnieuw hoe je de tabellen die Eloquent gebruikt aanmaakt met migraties.
</Card>


## Related topics

- [Introductie tot Eloquent-relaties](/nl/eloquent-relationships.md)
- [Eloquent-collecties](/nl/eloquent-collections.md)
- [Eloquent API-resources](/nl/eloquent-resources.md)
- [Databasemigraties](/nl/migrations.md)
- [MongoDB](/nl/mongodb.md)
