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

# Eloquent bootable traits

> Uitleg over het mechanisme waarmee traits in Eloquent-modellen automatisch worden opgestart. Je leert de naamgevingsconventie voor de methodes `bootXxx()` en `initializeXxx()`, en de expliciete aanduiding via PHP-attributes. Een veelgebruikt patroon in packageontwikkeling.

## Overzicht

Een Eloquent-model voert bij elke instantiatie een "opstartproces (boot)" en een "initialisatieproces (initialize)" uit. Definieer je deze methodes in een trait, dan worden ze automatisch aangeroepen zodra een model die trait `use`-t.

Met dit mechanisme kun je traits die functionaliteit in een model injecteren netjes implementeren. Het Laravel-framework zelf gebruikt dit patroon ook in veel traits, zoals `SoftDeletes`.

```mermaid theme={null}
sequenceDiagram
    participant App as Applicatie
    participant Model as Eloquent-model
    participant Trait as Trait

    App->>Model: new Post() of Post::find()
    Model->>Model: bootIfNotBooted()
    Model->>Trait: bootXxx() (alleen de eerste keer per klasse)
    Model->>Model: initializeTraits()
    Model->>Trait: initializeXxx() (per instantie)
    Model-->>App: Modelinstantie
```

***

## Het verschil tussen boot en initialize

|                   | `bootXxx()`                                                     | `initializeXxx()`                                               |
| ----------------- | --------------------------------------------------------------- | --------------------------------------------------------------- |
| **Aanroepmoment** | Bij de eerste boot van de modelklasse (één keer per klasse)     | Bij elke instantiatie                                           |
| **Type methode**  | `static`                                                        | Instantiemethode                                                |
| **Gebruik**       | Eventlisteners registreren, globale scopes toevoegen, enzovoort | Standaardwaarden instellen, properties initialiseren, enzovoort |

***

## Naamgevingsconventie

### bootXxx()

Definieer je een **`static`**-methode met de prefix `boot` gevolgd door de traitnaam, dan wordt die één keer aangeroepen bij het opstarten van het model.

```php theme={null}
namespace App\Models\Concerns;

trait HasSlug
{
    public static function bootHasSlug(): void
    {
        static::creating(function ($model) {
            if (empty($model->slug)) {
                $model->slug = str($model->name)->slug()->toString();
            }
        });
    }
}
```

Gebruik in het model:

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

class Article extends Model
{
    use HasSlug;
    // bootHasSlug() wordt automatisch aangeroepen
}
```

### initializeXxx()

Definieer je een instantiemethode met de prefix `initialize` gevolgd door de traitnaam, dan wordt die aangeroepen bij elke `new` van het model.

```php theme={null}
namespace App\Models\Concerns;

trait HasDefaultStatus
{
    public function initializeHasDefaultStatus(): void
    {
        $this->attributes['status'] ??= 'draft';
    }
}
```

Ook bruikbaar voor dynamische toevoegingen aan `$casts`:

```php theme={null}
trait HasMetadata
{
    public function initializeHasMetadata(): void
    {
        $this->mergeCasts([
            'metadata' => 'array',
        ]);
    }
}
```

***

## Expliciete aanduiding via PHP-attributes

Vanaf Laravel 12 kun je methodes expliciet aanwijzen met PHP-attributes, zonder afhankelijk te zijn van de naamgevingsconventie.

| Attribute       | Doel                                                                  |
| --------------- | --------------------------------------------------------------------- |
| `#[Boot]`       | Methode die één keer wordt uitgevoerd bij het opstarten van de klasse |
| `#[Initialize]` | Methode die bij elke instantiatie wordt uitgevoerd                    |

```php theme={null}
use Illuminate\Database\Eloquent\Attributes\Boot;
use Illuminate\Database\Eloquent\Attributes\Initialize;

trait HasAuditLog
{
    #[Boot]
    public static function registerAuditListeners(): void
    {
        static::created(function ($model) {
            AuditLog::record('created', $model);
        });

        static::updated(function ($model) {
            AuditLog::record('updated', $model);
        });
    }

    #[Initialize]
    public function setAuditDefaults(): void
    {
        $this->attributes['audit_enabled'] ??= true;
    }
}
```

<Info>
  Met PHP-attributes is de methodenaam niet gebonden aan de traitnaam, zodat je betekenisvolle namen kunt kiezen. Je kunt ook meerdere `#[Boot]`- of `#[Initialize]`-methodes in dezelfde trait definiëren.
</Info>

***

## Praktijkvoorbeelden: toepassing in packageontwikkeling

### Automatisch een globale scope toevoegen

```php theme={null}
trait HasTenant
{
    public static function bootHasTenant(): void
    {
        static::addGlobalScope(new TenantScope);
    }
}
```

### Standaardcasts toevoegen

```php theme={null}
trait HasJsonSettings
{
    public function initializeHasJsonSettings(): void
    {
        $this->mergeCasts([
            'settings' => 'array',
        ]);
    }
}
```

### Automatische verwerking via Eloquent-events

```php theme={null}
trait Archivable
{
    #[Boot]
    public static function bootArchivable(): void
    {
        static::deleting(function ($model) {
            Archive::store($model->toArray());
        });
    }
}
```

***

## Voorbeelden binnen het Laravel-framework

Het Laravel-framework zelf past dit patroon toe in veel traits.

| Trait         | Methode             | Wat er gebeurt                                   |
| ------------- | ------------------- | ------------------------------------------------ |
| `SoftDeletes` | `bootSoftDeletes()` | Voegt de globale scope voor soft deletes toe     |
| `HasFactory`  | `bootHasFactory()`  | Niets bijzonders (mechanisme buiten scopes)      |
| `HasUlids`    | `bootHasUlids()`    | Zet automatisch een ULID in het `creating`-event |
| `HasUuids`    | `bootHasUuids()`    | Zet automatisch een UUID in het `creating`-event |

Lees deze als referentie-implementaties om het patroon beter te begrijpen.

***

## Aandachtspunten

### De modelcache legen

Omdat `boot*` per klasse maar één keer wordt uitgevoerd, moet je opletten in de testomgeving. Met `Model::clearBootedModels()` reset je de cache van geboote modellen.

```php theme={null}
// De bootstatus van modellen resetten na een test
protected function tearDown(): void
{
    Model::clearBootedModels();
    parent::tearDown();
}
```

### Uitvoeringsvolgorde

`use`-t hetzelfde model meerdere traits, dan worden `bootXxx()` / `initializeXxx()` aangeroepen in de traitresolutievolgorde van PHP (declaratievolgorde). Let bij afhankelijkheden dus op de volgorde van de `use`-statements.

***

## Samenvatting

| Patroon                                    | Methode                              | Toepassing                                   |
| ------------------------------------------ | ------------------------------------ | -------------------------------------------- |
| Verwerking bij het opstarten van de klasse | `static bootXxx()` of `#[Boot]`      | Events registreren, globale scopes toevoegen |
| Initialisatie per instantie                | `initializeXxx()` of `#[Initialize]` | Standaardwaarden, casts toevoegen            |

Implementeer je `bootXxx()` / `initializeXxx()` in een trait, dan is het injecteren van functionaliteit in een model geregeld met één regel `use`. Hét standaardpatroon om vanuit een package functionaliteit aan modellen toe te voegen.


## Related topics

- [Dumpable-trait](/nl/advanced/dumpable.md)
- [Conditionable-trait](/nl/advanced/conditionable.md)
- [Eloquent-factories](/nl/eloquent-factories.md)
- [ForwardsCalls-trait](/nl/advanced/forwards-calls.md)
- [Scopes in Eloquent](/nl/advanced/eloquent-scopes.md)
