-
Notifications
You must be signed in to change notification settings - Fork 0
Relations Definition
BOUNDLY supports all major relationship types through declarative attributes. No manual pivot tables or foreign key configuration needed.
Infrastructure\FrameworkCore\Attributes\Relations\Declares that this entity belongs to another. Automatically creates the foreign key column.
| Parameter | Type | Default | Description |
|---|---|---|---|
relatedEntity |
string |
Required | The parent entity class name |
foreignKey |
string |
'' |
FK column name (auto-generated if empty) |
nullable |
bool |
true |
Allow NULL when no parent exists |
Use Case: When an entity has a reference to another entity (e.g., a Post belongs to a User).
Example:
use Infrastructure\FrameworkCore\Attributes\Schema\{Entity, Column};
use Infrastructure\FrameworkCore\Attributes\Relations\BelongsTo;
#[Entity(table: 'posts', resource: 'posts')]
class Post extends AggregateRoot
{
#[Id]
private int $id;
#[Column(type: 'string', length: 255)]
private string $title;
#[BelongsTo(relatedEntity: User::class)]
private array $author;
}Generated Schema:
CREATE TABLE posts (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255),
user_id BIGINT UNSIGNED NULL,
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
);API Behavior:
-
GET /api/postsincludes the related author -
POST /api/postsacceptsuser_idin payload
Declares the inverse side of a one-to-many relationship. No schema changes needed (handled by the BelongsTo side).
| Parameter | Type | Default | Description |
|---|---|---|---|
relatedEntity |
string |
Required | The child entity class name |
foreignKey |
string |
'' |
The FK column on the child entity |
Use Case: When an entity can have multiple related entities (e.g., a User has many Posts).
Example:
use Infrastructure\FrameworkCore\Attributes\Schema\{Entity, Column, Id};
use Infrastructure\FrameworkCore\Attributes\Relations\HasMany;
#[Entity(table: 'users', resource: 'users')]
class User extends AggregateRoot
{
#[Id]
private int $id;
#[Column(type: 'string', length: 150)]
private string $name;
#[HasMany(relatedEntity: Post::class)]
private array $posts;
}Declares a one-to-one relationship where this entity has one related entity.
| Parameter | Type | Default | Description |
|---|---|---|---|
relatedEntity |
string |
Required | The related entity class name |
foreignKey |
string |
'' |
The FK column on the related entity |
Use Case: When an entity has exactly one related entity (e.g., a User has one Profile).
Example:
use Infrastructure\FrameworkCore\Attributes\Schema\{Entity, Column, Id};
use Infrastructure\FrameworkCore\Attributes\Relations\HasOne;
#[Entity(table: 'users', resource: 'users')]
class User extends AggregateRoot
{
#[Id]
private int $id;
#[Column(type: 'string', length: 150)]
private string $name;
#[HasOne(relatedEntity: Profile::class)]
private array $profile;
}Creates a many-to-many relationship with an automatic pivot table.
| Parameter | Type | Default | Description |
|---|---|---|---|
relatedEntity |
string |
Required | The related entity class name |
pivotTable |
string |
'' |
Pivot table name (auto-generated if empty) |
foreignPivotKey |
string |
'' |
FK on pivot pointing to this entity |
relatedPivotKey |
string |
'' |
FK on pivot pointing to related entity |
Use Case: When entities can have multiple relationships with each other (e.g., Users have many Roles, Roles have many Users).
Example:
use Infrastructure\FrameworkCore\Attributes\Schema\{Entity, Column, Id};
use Infrastructure\FrameworkCore\Attributes\Relations\ManyToMany;
#[Entity(table: 'users', resource: 'users')]
class User extends AggregateRoot
{
#[Id]
private int $id;
#[Column(type: 'string', length: 150)]
private string $name;
#[ManyToMany(relatedEntity: Role::class)]
private array $roles;
}Generated Pivot Table:
CREATE TABLE role_user (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT UNSIGNED NOT NULL,
role_id BIGINT UNSIGNED NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
UNIQUE KEY role_user_unique (user_id, role_id)
);Custom Pivot Table Name:
#[ManyToMany(
relatedEntity: Role::class,
pivotTable: 'user_permissions',
foreignPivotKey: 'user_id',
relatedPivotKey: 'permission_id'
)]
private array $permissions;Using in API:
// POST /api/users
{
"name": "John Doe",
"roles": [1, 2, 3]
}
// GET /api/users?include=roles
{
"id": 1,
"name": "John Doe",
"roles": [
{"id": 1, "name": "Admin"},
{"id": 2, "name": "Editor"},
{"id": 3, "name": "Viewer"}
]
}Polymorphic relationships allow a model to belong to more than one other model on a single association. For example, you might have a Comment model that can belong to either a Post or a Video model.
One entity can be the parent of multiple other entity types (1→N polymorphic).
| Parameter | Type | Default | Description |
|---|---|---|---|
relatedEntity |
string |
Required | The child entity class name |
relation |
string |
Required | The polymorphic relation name |
Use Case: When an entity can have multiple comments of different types (e.g., Posts, Videos, Products all have comments).
Example:
use Infrastructure\FrameworkCore\Attributes\Schema\{Entity, Column, Id};
use Infrastructure\FrameworkCore\Attributes\Relations\MorphMany;
#[Entity(table: 'posts', resource: 'posts')]
class Post extends AggregateRoot
{
#[Id]
private int $id;
#[Column(type: 'string', length: 255)]
private string $title;
#[MorphMany(relatedEntity: Comment::class, relation: 'commentable')]
private array $comments;
}Child Entity (Comment):
use Infrastructure\FrameworkCore\Attributes\Schema\{Entity, Column, Id};
use Infrastructure\FrameworkCore\Attributes\Relations\MorphTo;
#[Entity(table: 'comments', resource: 'comments')]
class Comment extends AggregateRoot
{
#[Id]
private int $id;
#[Column(type: 'text')]
private string $body;
#[MorphTo]
private array $commentable;
}Generated Schema:
CREATE TABLE comments (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
body TEXT,
commentable_id BIGINT UNSIGNED NULL,
commentable_type VARCHAR(255) NULL,
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL
);One polymorphic relationship (1→1 polymorphic).
| Parameter | Type | Default | Description |
|---|---|---|---|
relatedEntity |
string |
Required | The child entity class name |
relation |
string |
Required | The polymorphic relation name |
Use Case: When an entity can have one image of different types (e.g., Users, Posts, Products all have one featured image).
Example:
use Infrastructure\FrameworkCore\Attributes\Schema\{Entity, Column, Id};
use Infrastructure\FrameworkCore\Attributes\Relations\MorphOne;
#[Entity(table: 'users', resource: 'users')]
class User extends AggregateRoot
{
#[Id]
private int $id;
#[Column(type: 'string', length: 150)]
private string $name;
#[MorphOne(relatedEntity: Image::class, relation: 'imageable')]
private array $avatar;
}The child side of a polymorphic relationship. Automatically creates {name}_id and {name}_type columns.
| Parameter | Type | Default | Description |
|---|---|---|---|
name |
string |
null |
Morph name (defaults to property name) |
Use Case: Define on the child entity to specify which entities can own it.
Example:
use Infrastructure\FrameworkCore\Attributes\Schema\{Entity, Column, Id};
use Infrastructure\FrameworkCore\Attributes\Relations\MorphTo;
#[Entity(table: 'images', resource: 'images')]
class Image extends AggregateRoot
{
#[Id]
private int $id;
#[Column(type: 'string', length: 500)]
private string $url;
#[MorphTo(name: 'imageable')]
private array $imageable;
}Load relationships efficiently using dot notation for nested relations:
# Single relation
GET /api/posts?include=author
# Multiple relations
GET /api/users?include=profile,posts
# Nested relations (posts → comments → author)
GET /api/users?include=posts.comments.author
# Polymorphic relations
GET /api/posts?include=comments
GET /api/videos?include=commentsPerformance: BOUNDLY automatically optimizes N+1 queries into efficient WHERE IN (...) calls.
| Relationship | Parent Attribute | Child Attribute | Schema Changes |
|---|---|---|---|
| One-to-Many | #[BelongsTo] |
#[HasMany] |
FK on child |
| One-to-One | #[BelongsTo] |
#[HasOne] |
FK on child |
| Many-to-Many | #[ManyToMany] |
#[ManyToMany] |
Pivot table created |
| Polymorphic (1→N) | #[MorphMany] |
#[MorphTo] |
FK + Type on child |
| Polymorphic (1→1) | #[MorphOne] |
#[MorphTo] |
FK + Type on child |
Next Step: Validation-Attributes ✅