Introducing One To One Relationship in Laravel

One of the core element of the Laravel framework is Eloquent ORM, which is an object-relational mapper. Laravel Eloquent provide a very user-friendly way to create a relationship between Eloquent models.

In this post, we will look at how we can create one to one relationship in Laravel with an example.

What is One To One Relationship?

One to One relationship links one row in a database table to one row in another database table. One to One relationship is a fundamental relation and very easy to use.

For example, in our application, we have a User model which is used for authentication purpose. Now we want to add a profile management section to store user’s social links, bio, date of birth and other user-related data. We can add the profile related columns in the user’s table but it will make the table messy.

So to keep our database clean, we want to store user authentication related data such as email address, username, and password in users table and profile related data like social links, bio, date of birth in profiles table.

As we know a single user can have a single profile and a profile belongs to a single user, so here we are creating a one to one relationship. This relationship is depicted in the below diagram.

One To One Relationship Diagram
One To One Relationship Diagram

Creating Model and Migration

To implement the one to one relationship in Laravel, we will need two models: User and Profile.

Note

I assume you have fresh installation of Laravel and have setup the database credentials in .env file.

As we know Laravel already shipped with a User model, so we need to create the Profile model which will map to profiles table in database.

To generate Profile model, we can use artisan command to generate model and migration. Run below command:

php artisan make:model Profile -m

Above command will generate a new model App\Profile with a migration file like below.

namespace App;

use Illuminate\Database\Eloquent\Model;

class Profile extends Model
{
    //
}

and migration file:

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateProfilesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('profiles', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('profiles');
    }
}

Firstly we will update the up method in migration file to look like below:

public function up()
    {
        Schema::create('profiles', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->integer('user_id')->unsigned()->nullable();
            $table->foreign('user_id')->references('id')->on('users');
            $table->date('dob');
            $table->text('bio');
            $table->string('facebook');
            $table->string('twitter');
            $table->string('github');
            $table->timestamps();
        });
    }

Now we will update the Profile model like below:

namespace App;

use Illuminate\Database\Eloquent\Model;

class Profile extends Model
{
    protected $table = 'profiles';

    protected $fillable = ['dob', 'bio', 'facebook', 'twitter', 'github'];
}

Once model and migration updated, run below command to create the tables.

php artisan migrate

Defining One To One Relationship in Laravel

Once you have your tables created, it’s time to define the one to one relationship. Open you User.php file located in app folder and add a new public method called profile in User model.

public function profile()
{
    return $this->hasOne(Profile::class);
}

We typically give the same name as the related model to public method like profile. This function return a hasOne relationship.

Defining Inverse One To One Relationship in Laravel

We can also add the inverse one to one relationship by adding a user method in the Profile model like below.

namespace App;

use Illuminate\Database\Eloquent\Model;

class Profile extends Model
{
    protected $table = 'profiles';

    protected $fillable = ['dob', 'bio', 'facebook', 'twitter', 'github'];

    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

We have added the user method which return a belongsTo relationship as a profile belongs to a user.

Retrieving One To One Relationship Data

Once you have defines the relation data, you can access the profile of a user by calling profile method on user object like below.

$user = User::find(1);
$userDob = $user->profile->dob;
$userBio = $user->profile->bio;

To retrieve the user profile, Laravel will look for a foriegn key in the profiles table names user_id matching it with the User’s id.

Creating a One To One Relationship

To create a one to one relationship, we will first create the child object which Profile object like below.

$profile = new Profile();
$profile->dob = '20-03-1999';
$profile->bio = 'A professional programmer.';

Now we will save the child object through the parent object like below:

$profile = new Profile();
$profile->dob = '20-03-1999';
$profile->bio = 'A professional programmer.';

$user = User::find(1);
$user->profile()->save($profile);

Deleting a One To One Relationship

Deleting a one to one relationship is same as creating. We firstly grab the parent object which is $user and then call the delete method on profile() method like below:

$user = User::find(1);
$user->profile()->delete();

What about if we delete the $user before deleting the profile, this will leave a orphaned profile in database.

One approach is to delete the profile first and then call the delete method on $user object. Sometime you might neglect this two-step procedure and leave an orphaned profile in the database.

Laravel provide an elegant way to delete the child records when a parent record is deleted. You can use the onDelete() method in your migration when defining the foriegn key like below:

public function up()
{
    Schema::create('profiles', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->integer('user_id')->unsigned()->nullable();
        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
        $table->date('dob');
        $table->text('bio');
        $table->string('facebook');
        $table->string('twitter');
        $table->string('github');
        $table->timestamps();
    });
}

With placing a cascading delete option, deleting a user from the database will automatically delete the corresponding profile.

Conclusion

That’s it for now. Next time we will look at other relationship method Laravel provides. If you have any question, please leave it in the comments box below.

Your little help will keep this site alive and help us to produce quality content for you.