API surface
01API contracts that keep nested product data readable.
The backend layer carries a lot of structural responsibility: relation includes, version-aware filtering, and model-specific constraints that let the product move without controllers turning into switchboards.
Include parsing
Accepting nested include paths and turning them into eager loads without leaking relation syntax through the whole app.
Constraint mapping
Keeping model-level handlers declarative so includes can stay flexible without becoming unsafe or bespoke.
Status logic
Normalizing live, draft, scheduled, and archived behavior so data rules stay consistent across clients.
Code sample
Declarative eager-loading with per-relation constraints
<?php
final class IncludeManager
{
public static function apply(Builder $query, array $requested, array $allowed): Builder
{
$with = [];
foreach ($requested as $path) {
$directive = self::parseDirective($path);
if ($directive === null || ! array_key_exists($directive->relation, $allowed)) {
continue;
}
$config = is_array($allowed[$directive->relation]) ? $allowed[$directive->relation] : [];
$with[$directive->relation] = self::buildEagerLoad($directive, $config);
}
return $with === [] ? $query : $query->with($with);
}
private static function parseDirective(string $path): ?IncludeDirective
{
[$relation, $constraint] = array_pad(explode(':', trim($path), 2), 2, null);
if ($relation === '') {
return null;
}
return new IncludeDirective($relation, $constraint);
}
private static function buildEagerLoad(IncludeDirective $directive, array $config): string|Closure
{
if ($directive->constraint === null) {
return $directive->relation;
}
$constraints = self::constraintsFor($config);
return static function (Builder $relationQuery) use ($directive, $constraints): void {
$handler = $constraints[$directive->constraint] ?? null;
if (! is_callable($handler)) {
return;
}
$handler($relationQuery);
};
}
private static function constraintsFor(array $config): array
{
$constraints = $config['constraints'] ?? [];
return is_array($constraints) ? $constraints : [];
}
}
final readonly class IncludeDirective
{
public function __construct(
public string $relation,
public ?string $constraint,
) {
}
}
Sample basis: Adapted from the API include layer used to keep eager-loading and relation constraints readable at the query boundary.
Production layer: The production version also handles nested relation paths, per-model constraint maps, and status-aware filtering logic.