Laravel one to one relationship with example

  • Laravel one to one relationship with example

    Sharing is Caring... Show some love :)

    “Laravel eloquent one to one relationship with example”: A one-to-one relationship is a very basic, fundamental Laravel eloquent relationship.

    Following our complete guide to Laravel relationships, it simply relates one entity to another.

    For instance, in our voting application, a User is associated with one Vote.

    If we were to describe this relationship, we could say:

    Each user has one vote”.

    Before we dive into the article, subscribe to get access to our free laravel tips that will improve your productivity.


    Defining a one-to-one relationship

    In order to define this relationship, we call the hasOne method on the entity that owns the relationship.

    Here’s a code snippet defining the relationship.

    <?php
    
    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Model;
    
    class User extends Model
    {
        /**
         * Get's this user's vote
         */
        public function vote()
        {
            return $this->hasOne(App\Models\Vote::class);
        }
    }

    What happens here is, we pass the name of the related model (the ::class property returns the full name of the class).

    Once we’ve defined this relationship, we can always easily get the vote associated with any user in our database using Eloquent’s dynamic properties.

    Querying one-to-one Relationship

    Eloquent’s dynamic properties allow us to query relationships and get the values as if they are properties defined on the object. 

    We could do something like this:

    <?php
      namespace App\Http\Controllers;
    
      use App\Models\User;
    
      class RandomController extends Controller {
       public function getUserVote(){
        $user = User::find(1); // Get a User Instance
        $vote = $user->vote; // Get the Vote that this User has
        // Do whatever with it
         return response(['vote' => $vote], 200);
       }
        
      }

    As you can see we can get this user’s vote as if it were a property of this user object.

    What actually happens under the hood by default is:

    When we access the vote property, Eloquent makes a database query to the votes table using the foreign key that points to the current user’s primary key on the user’s table.

    That’s why it’s called a dynamic property; because its values are not predefined, rather it’s gotten on the fly by a database call.

    Laravel Naming

    Now you may ask?

    How does Eloquent know the correct name of the primary/local key on the user’s table?

    And how does it know where to get that key (the foreign key) on the votes table?

    Well, let’s answer these questions. 

    First of all, the primary key of Laravel tables is called ID. It is possible to change this in the Model class.

    Laravel uses this primary key as the local key.

    Eloquent also has a convention for naming the foreign key on the votes table: we always append _id to the name of the model that owns the relationship.

    In our example, the votes table would have a column called user_id. This user_id would always point to the ID of the user that owns that vote.

    ALSO READ  How to implement Structured Logging in Adonisjs
    gzBpXNOv 1024x651 - Laravel one to one relationship with example

    You may also think at this point:

    Laravel Custom Keys

    This is fun and all, but what if I don’t want to use this convention? Or what if I have a different column I want to use as the foreign key or local key?

    Eloquent provides a convention for this too, and it’s like this:

    <?php
    
    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Model;
    
    class User extends Model
    {
        /**
         * Get's this user's vote
         */
        public function vote()
        {
            return $this->hasOne(App\Models\Vote::class, 'foreign_key', 'local_key');
        }
    }

    Looking at the snippet, we see that the hasOne method can accept up to three parameters.

    The first parameter is required, and it provides the full name of the Eloquent model that forms the relationship. 

    The second argument is optional, and it specifies the name of the foreign key.

    The foreign key is the column that Eloquent checks for when we call the dynamic property.

    What this means is if we actually wrote this method, Eloquent would look for the vote by checking for the column foreign_key on the votes, table to see if the value is the same on the local_key column of the user’s table.

    Did you get it? Please read it again if you didn’t.


    The third argument is optional, and it defines the local key on the entity that has the relationship.

    So in our snippet, if we didn’t put the third argument to be local_key, whenever Eloquent is checking for votes, it would check the default ID column.

    Note:  If you want to omit the second argument, but provide a value for the third one, simply put null as the second argument, meaning your code will look like this: 

    return $this->hasOne(App\Models\Vote::class, null, 'local_key);

    Take a break and subscribe to get access to our free laravel tips that will improve your productivity.

    Defining the Inverse of One to One Relationships

    In Laravel “one to one relationship” with an example, defining an inverse relationship is also made very easy and straightforward.

    Well, it’s fun to find the vote of each user.

    But what if we had a vote and we wanted to find the user that vote belongs to?

    Eloquent provides a convenient means of defining the inverse of One-to-One relationships. 

    If we want to define the relationship that states: “Each vote belongs to a user”, we use the belongsTo method like this:

    <?php
      namespace App\Models;
      use Illuminate\Database\Eloquent\Model;
    
      class Vote extends Model {
        /**
        * Get's this vote's owner
        */
        public function user() {
          return $this->belongsTo(App\Models\User::class); 
        }
      
      }

    Once this is defined, we can get our user just like we showed earlier by using the dynamic property.

    We would be able to call the user property on a vote instance as it existed.

    ALSO READ  Laravel 9 Tutorial: Laravel 9 new features

    In a similar fashion, Eloquent would run a database query behind the scenes that checks for the user_id column on the votes table and see if it matches a record with the same ID on the user’s table. 

    If you don’t want this convention, you can also define different foreign and local keys like we did above.

    So this snippet would look like this:

    
    <?php
      namespace App\Models;
    
      use Illuminate\Database\Eloquent\Model;
      
      class Vote extends Model {
       /**
       * Get's this vote's user
       */
       public function user() {
          return $this->belongsTo(App\Models\User::class, 'foreign_key', 'local_key'); 
       }
        
      }

    Just as explained earlier, with this we can set the foreign key (on the user’s table ) or the local key (on the vote’s table) to a different column by using the optional second and third parameters of the belongsTo method.

    Retrieving a One to One Relationship

    Once we’ve defined our relationship, it’s easy to get the values and start having fun with it.

    To get the value of the relationship, we simply use the dynamic property to get it.

    So, if we wanted to get our vote given a user, we would do:

    <?php
    
     use App\Models\User;
    
      class RandomClass {
       public function randomFunction(){
        $user = User::find(1); // Gets a User Instance
        $vote = $user->vote; // Gets the User's Vote
        // Do whatever with it
         print_r($vote);
       }
      }

    In addition to using dynamic properties to get the values of relationships, you can go further down the relationship to get the relationship of your relationship.

    So if we wanted to get the party our user voted for, and we already defined Laravel One-to-One relationships between Vote and PoliticalParty models, we can do this:

    <?php
    
     use App\Models\User;
    
      class RandomClass {
       public function randomFunction(){
        $user = User::find(1); // Gets a User Instance
        $vote = $user->vote->politicalParty; // Gets the party the user voted for
        // Do whatever with it
         print_r($vote);
       }
      }

    You can get an in-depth article on “Laravel one to many relationships with example” that explain everything from creating the relationship, the inverse method of creating it, and how to retrieve the data.

    Getting Started with Laravel One to One CRUD Example (Word Matching Game)

    In order to better illustrate one-to-one relationships, we’ve prepared a repository you can clone that shows one-to-one relationships in action.

    In this repository, we build a simple game where you pick the best word or words from the select box on the right that matches the word on the left.

    Feel free to clone the repository so we can get started.

    Jjq40xTI 1024x798 - Laravel one to one relationship with example

    Before we dive into the article, subscribe to get access to our free laravel tips that will improve your productivity.

    In order to run the application, you’d have install composer dependencies with:

    composer install

    Then you’d have to run the migrations (after creating a database and setting credentials in your  .env file of course:

    php artisan migrate

    Finally, we’d have to seed the database:

    php artisan db:seed

    The application stores two entities, Word and Match and they have a One to One relationship.

    ALSO READ  Top 5 backend frameworks

    Every word has a match, and every match belongs to a word.

    We define this relationship in app/Models/Word.php and app/Models/Match.php respectively:

    <?php
    // app/Models/Word.php
    namespace App\Models;
    use Illuminate\Database\Eloquent\Factories\HasFactory;
    use Illuminate\Database\Eloquent\Model;
    class Word extends Model
    {
        use HasFactory;
        // Define the One to One Relationship
        public function match() {
            return $this->hasOne(Match::class);
        }
    }
    <?php
    // app/Models/Word.php
    namespace App\Models;
    use Illuminate\Database\Eloquent\Factories\HasFactory;
    use Illuminate\Database\Eloquent\Model;
    class Match extends Model
    {
        use HasFactory;
        // Define the inverse of the relationship
        public function word()
        {
            return $this->belongsTo(Word::class);
        }
    }

    Finally, we use the relationship in the controller that the homepage’s form submits to, we use the inverse relationship to loop through the submitted values and increment the score (we could have used the default relationship too).

    <?php
    namespace App\Http\Controllers;
    use App\Models\Match;
    use App\Models\Word;
    use Illuminate\Http\Request;
    class WordMatcher extends Controller
    {
        public function submit(Request $request)
        {
            $matches = $request->input('match');
            // Gets all words as a collection in the same order they are shown on the page
            $words = Word::orderBy('value', 'asc')->get();
            $total = $words->count();
            $score = 0;
            foreach ($matches as $key => $match) {
                // Loop through the submitted words and use the inverse relationship to check if they are related.
                if (Match::find($match)->word->id === $words[$key]->id)
                    $score += 1;
    
                // The check could also be achieved by using the actual One to One relationship like this:
                // if($words[$key]->match->id == $match)
                //     $score += 1;
    
                /******************************
                 *
                 * N.B
                 *
                 * Using strict equality (===) in the commented if statemen with the actual relationship
                 * won't work because $match is a string while -> id returns an integer,
                 * and the types are not the same
                 *
                 *****************************/
            }
            $percent = floor(($score / $total) * 100);
            session()->flash("score_status", "success");
            session()->flash("score_status_title", "Here's your Score");
            session()->flash('score_status_message', "You got $percent% and matched $score out of $total words correctly.");
            return back();
        }
    }

    The rest of the code in the repository are frontend code, and the code to render the words and matches on the frontend.

    What’s Next?

    You can get an in-depth article on “Laravel one to many relationships with example” that explain everything from creating the relationship, the inverse method of creating it, and how to retrieve the data.

    Conclusion

    In this article, we had an in-depth look at Laravel’s “One to One relationships”, as well as an application implementing the relationship to solve a problem.

    One to One relationships are basic and help in writing applications in a more fluent way.  

    Feel free to check out our other articles where we similarly go in-depth to explain other Laravel relationships.

    Feel free to let us know if you have any questions and we’d love to help.

    Start Learning Backend Dev. Now

    Stop waiting and start learning! Get my 10 tips on teaching yourself backend development.

    Don't worry. I'll never, ever spam you!

    Sharing is caring :)

    Start Learning Now
    Learning for all. Savings for you. Courses from $11.99

    Comments