Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/betoalien/Lyger-PHP-Framework/llms.txt

Use this file to discover all available pages before exploring further.

Introduction

Eloquent makes it easy to manage relationships between database tables. Lyger supports several types of relationships including One-to-One, One-to-Many, and Many-to-Many, allowing you to work with related data in an expressive and intuitive way.

Relationship Types

Lyger supports the following relationship types:
  • One-to-One: hasOne() and belongsTo()
  • One-to-Many: hasMany() and belongsTo()
  • Many-to-Many: belongsToMany()

One-to-One Relationships

Defining the Relationship

A one-to-one relationship is used when one record is related to exactly one other record.
app/Models/User.php
<?php

namespace App\Models;

use Lyger\Database\Model;

class User extends Model
{
    protected string $table = 'users';
    protected array $fillable = ['name', 'email', 'password'];
    
    public function profile()
    {
        return $this->hasOne(Profile::class);
    }
}
app/Models/Profile.php
<?php

namespace App\Models;

use Lyger\Database\Model;

class Profile extends Model
{
    protected string $table = 'profiles';
    protected array $fillable = ['user_id', 'bio', 'avatar', 'location'];
    
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

Database Structure

-- users table
CREATE TABLE users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name VARCHAR(255),
    email VARCHAR(255),
    created_at TEXT,
    updated_at TEXT
);

-- profiles table
CREATE TABLE profiles (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER,
    bio TEXT,
    avatar VARCHAR(255),
    location VARCHAR(255),
    created_at TEXT,
    updated_at TEXT
);

Using the Relationship

// Get user's profile
$user = User::find(1);
$profile = $user->profile()->get();

if ($profile) {
    echo $profile->bio;
    echo $profile->location;
}

// Get profile's user
$profile = Profile::find(1);
$user = $profile->user()->get();

echo $user->name;
echo $user->email;

One-to-Many Relationships

Defining the Relationship

A one-to-many relationship is used when one record can have multiple related records.
app/Models/User.php
<?php

namespace App\Models;

use Lyger\Database\Model;

class User extends Model
{
    protected string $table = 'users';
    protected array $fillable = ['name', 'email'];
    
    public function posts()
    {
        return $this->hasMany(Post::class);
    }
}
app/Models/Post.php
<?php

namespace App\Models;

use Lyger\Database\Model;

class Post extends Model
{
    protected string $table = 'posts';
    protected array $fillable = ['user_id', 'title', 'content', 'status'];
    
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

Database Structure

-- users table
CREATE TABLE users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name VARCHAR(255),
    email VARCHAR(255),
    created_at TEXT,
    updated_at TEXT
);

-- posts table
CREATE TABLE posts (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER,
    title VARCHAR(255),
    content TEXT,
    status VARCHAR(50),
    created_at TEXT,
    updated_at TEXT
);

Using the Relationship

// Get all posts for a user
$user = User::find(1);
$posts = $user->posts()->get();

foreach ($posts as $post) {
    echo $post->title;
    echo $post->content;
}

// Get first post
$firstPost = $user->posts()->first();

// Count posts
$postCount = $user->posts()->count();

// Get post's author
$post = Post::find(1);
$author = $post->user()->get();

echo $author->name;

Many-to-Many Relationships

Defining the Relationship

A many-to-many relationship is used when records on both sides can have multiple related records.
app/Models/Post.php
<?php

namespace App\Models;

use Lyger\Database\Model;

class Post extends Model
{
    protected string $table = 'posts';
    protected array $fillable = ['title', 'content'];
    
    public function tags()
    {
        return $this->belongsToMany(Tag::class);
    }
}
app/Models/Tag.php
<?php

namespace App\Models;

use Lyger\Database\Model;

class Tag extends Model
{
    protected string $table = 'tags';
    protected array $fillable = ['name', 'slug'];
    
    public function posts()
    {
        return $this->belongsToMany(Post::class);
    }
}

Database Structure

-- posts table
CREATE TABLE posts (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    title VARCHAR(255),
    content TEXT,
    created_at TEXT,
    updated_at TEXT
);

-- tags table
CREATE TABLE tags (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name VARCHAR(100),
    slug VARCHAR(100),
    created_at TEXT,
    updated_at TEXT
);

-- post_tag pivot table (alphabetically ordered)
CREATE TABLE post_tag (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    post_id INTEGER,
    tag_id INTEGER,
    created_at TEXT,
    updated_at TEXT
);
The pivot table name is automatically determined by combining the related model names in alphabetical order: post_tag. You can customize this by passing a second parameter to belongsToMany().

Using the Relationship

// Get all tags for a post
$post = Post::find(1);
$tags = $post->tags()->get();

foreach ($tags as $tag) {
    echo $tag->name;
}

// Get all posts with a specific tag
$tag = Tag::find(1);
$posts = $tag->posts()->get();

foreach ($posts as $post) {
    echo $post->title;
}

Custom Foreign Keys

One-to-One and One-to-Many

By default, Eloquent assumes the foreign key is {model_name}_id. You can customize this:
// Custom foreign key in hasOne
public function profile()
{
    return $this->hasOne(Profile::class, 'custom_user_id');
}

// Custom foreign key in hasMany
public function posts()
{
    return $this->hasMany(Post::class, 'author_id');
}

// Custom foreign key in belongsTo
public function user()
{
    return $this->belongsTo(User::class, 'author_id');
}

Many-to-Many

Customize the pivot table name and keys:
public function tags()
{
    return $this->belongsToMany(
        Tag::class,          // Related model
        'custom_pivot_table' // Custom pivot table name
    );
}

Relationship Methods

hasOne()

Defines a one-to-one relationship (parent side).
The fully qualified class name of the related model
foreignKey
string
The foreign key on the related model (defaults to {model}_id)
public function profile()
{
    return $this->hasOne(Profile::class);
}

// With custom foreign key
public function profile()
{
    return $this->hasOne(Profile::class, 'custom_user_id');
}

hasMany()

Defines a one-to-many relationship (parent side).
The fully qualified class name of the related model
foreignKey
string
The foreign key on the related model (defaults to {model}_id)
public function posts()
{
    return $this->hasMany(Post::class);
}

// With custom foreign key
public function posts()
{
    return $this->hasMany(Post::class, 'author_id');
}

belongsTo()

Defines the inverse of a one-to-one or one-to-many relationship.
The fully qualified class name of the related model
foreignKey
string
The foreign key on this model (defaults to {related_model}_id)
public function user()
{
    return $this->belongsTo(User::class);
}

// With custom foreign key
public function author()
{
    return $this->belongsTo(User::class, 'author_id');
}

belongsToMany()

Defines a many-to-many relationship.
The fully qualified class name of the related model
pivotTable
string
The name of the pivot table (defaults to alphabetically ordered model names)
public function tags()
{
    return $this->belongsToMany(Tag::class);
}

// With custom pivot table
public function tags()
{
    return $this->belongsToMany(Tag::class, 'article_tags');
}

Complete Example

Here’s a comprehensive example with multiple relationship types:
app/Models/User.php
<?php

namespace App\Models;

use Lyger\Database\Model;

class User extends Model
{
    protected string $table = 'users';
    
    protected array $fillable = [
        'name',
        'email',
        'password'
    ];
    
    protected array $hidden = ['password'];
    
    // One-to-One: User has one Profile
    public function profile()
    {
        return $this->hasOne(Profile::class);
    }
    
    // One-to-Many: User has many Posts
    public function posts()
    {
        return $this->hasMany(Post::class);
    }
    
    // One-to-Many: User has many Comments
    public function comments()
    {
        return $this->hasMany(Comment::class);
    }
}
app/Models/Post.php
<?php

namespace App\Models;

use Lyger\Database\Model;

class Post extends Model
{
    protected string $table = 'posts';
    
    protected array $fillable = [
        'user_id',
        'title',
        'content',
        'status'
    ];
    
    protected array $casts = [
        'published' => 'bool'
    ];
    
    // Many-to-One: Post belongs to User
    public function user()
    {
        return $this->belongsTo(User::class);
    }
    
    // One-to-Many: Post has many Comments
    public function comments()
    {
        return $this->hasMany(Comment::class);
    }
    
    // Many-to-Many: Post has many Tags
    public function tags()
    {
        return $this->belongsToMany(Tag::class);
    }
}
app/Models/Comment.php
<?php

namespace App\Models;

use Lyger\Database\Model;

class Comment extends Model
{
    protected string $table = 'comments';
    
    protected array $fillable = [
        'user_id',
        'post_id',
        'content'
    ];
    
    // Many-to-One: Comment belongs to User
    public function user()
    {
        return $this->belongsTo(User::class);
    }
    
    // Many-to-One: Comment belongs to Post
    public function post()
    {
        return $this->belongsTo(Post::class);
    }
}
app/Models/Tag.php
<?php

namespace App\Models;

use Lyger\Database\Model;

class Tag extends Model
{
    protected string $table = 'tags';
    
    protected array $fillable = ['name', 'slug'];
    
    // Many-to-Many: Tag has many Posts
    public function posts()
    {
        return $this->belongsToMany(Post::class);
    }
}

Using the Relationships

// Get user with all relationships
$user = User::find(1);

// Get user's profile
$profile = $user->profile()->get();
echo $profile->bio;

// Get user's posts
$posts = $user->posts()->get();
foreach ($posts as $post) {
    echo $post->title;
    
    // Get post's tags
    $tags = $post->tags()->get();
    foreach ($tags as $tag) {
        echo $tag->name;
    }
    
    // Get post's comments
    $comments = $post->comments()->get();
    foreach ($comments as $comment) {
        echo $comment->content;
        
        // Get comment author
        $author = $comment->user()->get();
        echo $author->name;
    }
}

// Get user's comments
$comments = $user->comments()->get();
echo "Total comments: " . $comments->count();

// Get all posts with a specific tag
$tag = Tag::find(1);
$taggedPosts = $tag->posts()->get();

Collection Methods on Relationships

Relationship results return Collection instances with useful methods:
$user = User::find(1);
$posts = $user->posts()->get();

// Count
$count = $posts->count();

// First
$latestPost = $posts->first();

// Filter
$published = $posts->filter(fn($post) => $post->status === 'published');

// Map
$titles = $posts->map(fn($post) => $post->title);

// Sort
$sortedPosts = $posts->sortByDesc('created_at');

// Take
$recentPosts = $posts->sortByDesc('created_at')->take(5);

Best Practices

1

Use Descriptive Method Names

Name relationship methods clearly based on what they return:
public function posts() // Returns multiple posts
public function user()  // Returns single user
public function profile() // Returns single profile
2

Define Inverse Relationships

Always define both sides of a relationship:
// User.php
public function posts() {
    return $this->hasMany(Post::class);
}

// Post.php
public function user() {
    return $this->belongsTo(User::class);
}
3

Use Type Hints

Document return types for better IDE support:
/**
 * @return HasMany
 */
public function posts()
{
    return $this->hasMany(Post::class);
}
4

Follow Naming Conventions

Use standard naming for pivot tables and foreign keys:
  • Pivot tables: alphabetically ordered model names (post_tag)
  • Foreign keys: {model}_id (e.g., user_id)

Migration Examples

One-to-Many Migration

// Create posts table with user_id foreign key
public function up(): void
{
    $this->getSchema()->create('posts', function ($table) {
        $table->id();
        $table->integer('user_id')->unsigned();
        $table->string('title');
        $table->text('content');
        $table->timestamps();
        
        // Add index for better query performance
        $table->index(['user_id']);
    });
}

Many-to-Many Migration

// Create pivot table for posts and tags
public function up(): void
{
    $this->getSchema()->create('post_tag', function ($table) {
        $table->id();
        $table->integer('post_id')->unsigned();
        $table->integer('tag_id')->unsigned();
        $table->timestamps();
        
        // Composite index for unique pairs
        $table->index(['post_id', 'tag_id']);
    });
}

Next Steps

Eloquent Models

Learn more about Eloquent model features

Query Builder

Understand the underlying Query Builder