Skip to content

Relationships ​

Introduction ​

Expressive can convert loaded Eloquent relationships into nested Expressive objects. Relationship conversion is opt-in at the property level with the #[Relationship] attribute and opt-in at runtime by loading or requesting the relationship.

Expressive does not trigger lazy loading for unloaded relationships. If a relationship was not loaded, the Expressive property is null.

Defining relationship properties ​

Single related models may be typed as the related Expressive class:

php
use WendellAdriel\Expressive\Attributes\Relationship;

#[Relationship]
public ?Address $address = null;

Relationships that return many models should use Illuminate\Support\Collection and a PHPDoc item type:

php
use Illuminate\Support\Collection;
use WendellAdriel\Expressive\Attributes\Relationship;

/** @var Collection<int, Post>|null */
#[Relationship]
public ?Collection $posts = null;

Relationship properties must be nullable because Expressive uses null when the relationship is unavailable.

Loading relationships ​

Pass relationships to expressive() to load them before conversion:

php
$user = User::query()->findOrFail(1)->expressive(
    relationships: ['address', 'posts'],
);

You may pass a single relationship name or an array of relationship names:

php
$user = User::query()->findOrFail(1)->expressive(relationships: 'posts');

For collections and builders, requested relationships are loaded before each model is converted:

php
$users = User::query()->get()->expressive(relationships: ['posts']);

Relationship conversion ​

Loaded single-model relationships become nested Expressive objects:

php
$user->address; // App\Expressive\Address|null

Loaded many-model relationships become collections of Expressive objects:

php
$user->posts; // Illuminate\Support\Collection<int, App\Expressive\Post>|null

Nested conversion uses the same model-to-Expressive resolution rules as root conversion. The related model may use an explicit #[Expressive] attribute or the configured namespace and suffix.

Polymorphic relationships ​

The generator can create broad PHPDoc hints for MorphTo relationships because the related model is not known from the relationship definition alone:

php
use Illuminate\Database\Eloquent\Model;
use WendellAdriel\Expressive\Expressive;
use WendellAdriel\Expressive\Attributes\Relationship;

/** @var Expressive<Model>|null */
#[Relationship]
public ?Expressive $imageable = null;

If your application has a morph map, the generator may add more specific PHPDoc hints when --hint-morph-map is enabled and the inverse relationship can be resolved confidently.

Runtime conversion does not change because of morph-map hints. Expressive converts the actual loaded related model.

Relationship persistence ​

Expressive can persist direct relationships when you call save() on the Expressive object. Supported relationship writes are documented in the persistence guide.

Many-to-many and through relationship persistence is intentionally unsupported. Convert to Eloquent and use explicit application code for attach, sync, detach, or through-model workflows.