Eloquent relationships: one-to-one, one-to-many, many-to-many, and how to fetch and display related data

 To create a Laravel project with various relationships (one-to-one, one-to-many, hasManyThrough, belongsTo, and many-to-many), we can create a simple scenario involving `User`, `Profile`, `Post`, `Comment`, and `Role` models.


### Step 1: Create a New Laravel Project


If you haven't already, create a new Laravel project:


```bash

composer create-project --prefer-dist laravel/laravel RelationshipDemo

cd RelationshipDemo

```


### Step 2: Set Up the Models and Migrations


We'll create the following models and migrations:


1. **User**: Has a one-to-one relationship with `Profile`, one-to-many with `Post`, and a many-to-many relationship with `Role`.

2. **Profile**: Belongs to `User`.

3. **Post**: Belongs to `User` and has many `Comment`s.

4. **Comment**: Belongs to `Post`.

5. **Role**: Belongs to many `User`s.


Run the following commands to create the models and migrations:


```bash

php artisan make:model User -m

php artisan make:model Profile -m

php artisan make:model Post -m

php artisan make:model Comment -m

php artisan make:model Role -m

php artisan make:migration create_role_user_table --create=role_user

```


### Step 3: Define the Relationships in Models and Migrations


#### User Model


```php

// app/Models/User.php

namespace App\Models;


use Illuminate\Database\Eloquent\Factories\HasFactory;

use Illuminate\Foundation\Auth\User as Authenticatable;


class User extends Authenticatable

{

    use HasFactory;


    public function profile()

    {

        return $this->hasOne(Profile::class);

    }


    public function posts()

    {

        return $this->hasMany(Post::class);

    }


    public function roles()

    {

        return $this->belongsToMany(Role::class);

    }

}

```


#### Profile Model


```php

// app/Models/Profile.php

namespace App\Models;


use Illuminate\Database\Eloquent\Factories\HasFactory;

use Illuminate\Database\Eloquent\Model;


class Profile extends Model

{

    use HasFactory;


    public function user()

    {

        return $this->belongsTo(User::class);

    }

}

```


#### Post Model


```php

// app/Models/Post.php

namespace App\Models;


use Illuminate\Database\Eloquent\Factories\HasFactory;

use Illuminate\Database\Eloquent\Model;


class Post extends Model

{

    use HasFactory;


    public function user()

    {

        return $this->belongsTo(User::class);

    }


    public function comments()

    {

        return $this->hasMany(Comment::class);

    }

}

```


#### Comment Model


```php

// app/Models/Comment.php

namespace App\Models;


use Illuminate\Database\Eloquent\Factories\HasFactory;

use Illuminate\Database\Eloquent\Model;


class Comment extends Model

{

    use HasFactory;


    public function post()

    {

        return $this->belongsTo(Post::class);

    }

}

```


#### Role Model


```php

// app/Models/Role.php

namespace App\Models;


use Illuminate\Database\Eloquent\Factories\HasFactory;

use Illuminate\Database\Eloquent\Model;


class Role extends Model

{

    use HasFactory;


    public function users()

    {

        return $this->belongsToMany(User::class);

    }

}

```


#### Migrations


Edit the migration files to define the schema for the tables.


##### Users Migration


```php

// database/migrations/xxxx_xx_xx_create_users_table.php

use Illuminate\Database\Migrations\Migration;

use Illuminate\Database\Schema\Blueprint;

use Illuminate\Support\Facades\Schema;


class CreateUsersTable extends Migration

{

    public function up()

    {

        Schema::create('users', function (Blueprint $table) {

            $table->id();

            $table->string('name');

            $table->string('email')->unique();

            $table->string('password');

            $table->timestamps();

        });

    }


    public function down()

    {

        Schema::dropIfExists('users');

    }

}

```


##### Profiles Migration


```php

// database/migrations/xxxx_xx_xx_create_profiles_table.php

use Illuminate\Database\Migrations\Migration;

use Illuminate\Database\Schema\Blueprint;

use Illuminate\Support\Facades\Schema;


class CreateProfilesTable extends Migration

{

    public function up()

    {

        Schema::create('profiles', function (Blueprint $table) {

            $table->id();

            $table->foreignId('user_id')->constrained()->onDelete('cascade');

            $table->string('bio')->nullable();

            $table->string('address')->nullable();

            $table->timestamps();

        });

    }


    public function down()

    {

        Schema::dropIfExists('profiles');

    }

}

```


##### Posts Migration


```php

// database/migrations/xxxx_xx_xx_create_posts_table.php

use Illuminate\Database\Migrations\Migration;

use Illuminate\Database\Schema\Blueprint;

use Illuminate\Support\Facades\Schema;


class CreatePostsTable extends Migration

{

    public function up()

    {

        Schema::create('posts', function (Blueprint $table) {

            $table->id();

            $table->foreignId('user_id')->constrained()->onDelete('cascade');

            $table->string('title');

            $table->text('content');

            $table->timestamps();

        });

    }


    public function down()

    {

        Schema::dropIfExists('posts');

    }

}

```


##### Comments Migration


```php

// database/migrations/xxxx_xx_xx_create_comments_table.php

use Illuminate\Database\Migrations\Migration;

use Illuminate\Database\Schema\Blueprint;

use Illuminate\Support\Facades\Schema;


class CreateCommentsTable extends Migration

{

    public function up()

    {

        Schema::create('comments', function (Blueprint $table) {

            $table->id();

            $table->foreignId('post_id')->constrained()->onDelete('cascade');

            $table->text('body');

            $table->timestamps();

        });

    }


    public function down()

    {

        Schema::dropIfExists('comments');

    }

}

```


##### Roles Migration


```php

// database/migrations/xxxx_xx_xx_create_roles_table.php

use Illuminate\Database\Migrations\Migration;

use Illuminate\Database\Schema\Blueprint;

use Illuminate\Support\Facades\Schema;


class CreateRolesTable extends Migration

{

    public function up()

    {

        Schema::create('roles', function (Blueprint $table) {

            $table->id();

            $table->string('name');

            $table->timestamps();

        });

    }


    public function down()

    {

        Schema::dropIfExists('roles');

    }

}

```


##### Role_User Pivot Table Migration


```php

// database/migrations/xxxx_xx_xx_create_role_user_table.php

use Illuminate\Database\Migrations\Migration;

use Illuminate\Database\Schema\Blueprint;

use Illuminate\Support\Facades\Schema;


class CreateRoleUserTable extends Migration

{

    public function up()

    {

        Schema::create('role_user', function (Blueprint $table) {

            $table->id();

            $table->foreignId('role_id')->constrained()->onDelete('cascade');

            $table->foreignId('user_id')->constrained()->onDelete('cascade');

            $table->timestamps();

        });

    }


    public function down()

    {

        Schema::dropIfExists('role_user');

    }

}

```


### Step 4: Run the Migrations


Run the migrations to create the tables in the database:


```bash

php artisan migrate

```


### Step 5: Seed the Database with Dummy Data (Optional)


You can use Laravel's seeding feature to populate the database with dummy data for testing:


```bash

php artisan make:seeder DatabaseSeeder

```


Edit the `DatabaseSeeder.php` file:


```php

// database/seeders/DatabaseSeeder.php

use Illuminate\Database\Seeder;

use App\Models\User;

use App\Models\Profile;

use App\Models\Post;

use App\Models\Comment;

use App\Models\Role;


class DatabaseSeeder extends Seeder

{

    public function run()

    {

        // Create some roles

        $adminRole = Role::create(['name' => 'Admin']);

        $editorRole = Role::create(['name' => 'Editor']);

        

        // Create a user and assign roles

        $user = User::factory()->create(['name' => 'John Doe']);

        $user->roles()->attach([$adminRole->id, $editorRole->id]);


        // Create a profile for the user

        Profile::create([

            'user_id' => $user->id,

            'bio' => 'This is John Doe\'s profile.',

            'address' => '123 Main St.',

        ]);


        // Create posts and comments

        $posts = Post::factory()->count(3)->create(['user_id' => $user->id]);

        foreach ($posts as $post) {

            Comment::factory()->count(2)->create(['post_id' => $post->id]);

        }

    }

}

```


Run the seeder:


```bash

php artisan db:seed

```


### Step 6: Display the Relationships in a Controller


Create a controller to display data from the relationships:


```bash

php artisan make:controller TestController

```


In the `TestController.php` file, add the following methods to display related data:


```php

// app/Http/Controllers/TestController.php

namespace App\Http\Controllers;


use App\Models\User;

use Illuminate\Http\Request;


class TestController extends Controller

{

    public function showUserProfile($userId)

    {

        $user = User::with('profile')->findOrFail($userId);

        return view('user.profile', compact('user'));

    }


    public function showUserPosts($userId)

    {

        $user = User::with('posts')->findOrFail($userId);

        return view('user.posts', compact


('user'));

    }


    public function showPostComments($postId)

    {

        $post = Post::with('comments')->findOrFail($postId);

        return view('post.comments', compact('post'));

    }


    public function showUserRoles($userId)

    {

        $user = User::with('roles')->findOrFail($userId);

        return view('user.roles', compact('user'));

    }

}

```


### Step 7: Create Views to Display the Data


For example, to show the user's profile:


```blade

<!-- resources/views/user/profile.blade.php -->

<h1>{{ $user->name }}'s Profile</h1>

<p>Bio: {{ $user->profile->bio }}</p>

<p>Address: {{ $user->profile->address }}</p>

```


And for the posts:


```blade

<!-- resources/views/user/posts.blade.php -->

<h1>{{ $user->name }}'s Posts</h1>

@foreach($user->posts as $post)

    <h2>{{ $post->title }}</h2>

    <p>{{ $post->content }}</p>

@endforeach

```


### Step 8: Define Routes for Testing


Add routes in `web.php` to access these methods:


```php

// routes/web.php

use App\Http\Controllers\TestController;


Route::get('/user/{id}/profile', [TestController::class, 'showUserProfile']);

Route::get('/user/{id}/posts', [TestController::class, 'showUserPosts']);

Route::get('/post/{id}/comments', [TestController::class, 'showPostComments']);

Route::get('/user/{id}/roles', [TestController::class, 'showUserRoles']);

```


### Step 9: Test the Application


Visit the routes like `/user/1/profile`, `/user/1/posts`, etc., in your browser to see the relationships in action.


### Summary


This project demonstrates a basic Laravel application with various Eloquent relationships: one-to-one, one-to-many, many-to-many, and how to fetch and display related data. You can extend this further by adding more complex logic or relationships depending on your application's needs.

Comments

Popular posts from this blog

IMPORTANT INTERVIEW RELATED QUESTION

C++ Interview Questions

SUBLIME TEXT CHEAT SHEET