DARK MODE 

Posted on Friday, December 31, 2021 by

Create Instagram Clone with Laravel (Part 7): Create a New Model & Fetch User's Profile From Database to Display in View

Focus, everyone! As this is, by far, the most confusing part in the video for me. We're going to work with model and migration.

In this post, I covered from minute 1:10:05 until 1:28:10 of this video.

In our profile page, besides username, we have profile title, profile description and profile url. We can get the username from the User model, which holds all the data of a user. For additional data of a user, we need to use a different model. We're not going to put these additional data in the User model because 'user' and 'profile' are two different thing. So now, we're going to create a new model for user's profile. 


Create a new model

To create a new model, we use the make:model command. We also need to create a new migration for that model because we need to describe something new in our database. If we're going to represent something in our database, then we need to describe it inside a migration file. If you view the help screen for make:model, you can see that one of the options you can use is -m which will create a new migration file the model. Run php artisan make:model Profile -m to create a new model and migration file for that model.


Describing the database in migration

We've created a model and migration! Let's open the new migration file to describe our database. This part gave me a little headache at first so to get a clear overview, I created a simple ERD.

One user has only one profile (1-to-1 relationship). A profile has a foreign key of user id.

Now I'm clear on what we need to add in the new migration file. 

 14
 15
 16
 17
 18
 19
 20
 21
 22
23
24
25
26
    public function up()
    {
        Schema::create('profiles', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('user_id');
            $table->string('title')->nullable();
            $table->text('description')->nullable();
            $table->string('url')->nullable();
            $table->timestamps();

            $table->index('user_id');
        });
    }
database > migrations > 2021_12_28_130508_create_profiles_table.php

Line 18: user_id is used here and not other names to follow convention because we're associating this to the id of the User model
Line 19: Title is a type of string and the value can be null
Line 20: Description is a type of text because user can input longer strings and the value can be null
Line 21: Url is a type of string and the value can be null
Line 24: index(); is for better searchability and quicker queries

In the video, the instructor use unsignedBigInteger instead of foreignId on line 18. Based on this documentation of Laravel 7, unsignedBigInteger is just the alias for foreignId, to indicate that the column is a foreign key. Both are useable but because by default in Laravel 8, on line 17, is using $table->id(); instead of $table->bigIncrements('id');, I decided to use foreignId.

Instruct Laravel to handle one-to-one relationship

Next, we need to instruct Laravel on how to handle the one-to-one relationship of User and Profile properly. First, let's edit the Profile model. We need to tell that a profile is belong to User class so the profile will be able to fetch the user data. Again, it is important to use a particular name convention for the function name which is user. Why user? Because it is referring to the User model.

8
9
10
11
12
13
14
15
class Profile extends Model
{
    use HasFactory;
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}
app > Models > Profile.php

Now, we need to do the inverse so that the user can fetch the profile data too. We declared that the user has one Profile class. Again, follow naming convention which is profile for the function name because it is referring to the Profile model.

45
46
47
48
    public function profile()
    {
        return $this->hasOne(Profile::class);
    }
app > Models > User.php

Manually inserting data to the table

Everything's ready. If you still remember, if we want to interact with out database, we do it with Tinker. Now, before we insert user's profile data manually with Tinker, remember, whenever we described something new in the migration file, we need to run migration with php artisan migrate. Else, you will receive this kind of error when you want to save changes in Tinker later:

[Illuminate\Database\QueryException] SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint (SQL: alter table `priorities` add constraint priorities_user_id_foreign foreign key (`user_id`) references `users` (`id`))     

After migration is complete, enter these commands one by one.

  • php artisan tinker - enter Tinker
  • $profile = new Profile(); - you can also write it as $profile = new App\Models\Profile(); , like was taught in the video. This is to create a variable that creates a new Profile
  • $profile->title = 'Cool Title'; - This will insert 'Cool Title' as the profile title
  • $profile->description = 'Description'; - This will insert 'Description' as the profile description
  • $profile->user_id = 1; - Assign this profile to user id of 1 because if you save without assigning it, you get an error as user_id cannot be null
  • $profile->save(); - Save changes made
We'll enter the value for url later because we will learn to insert it using another method. If you by any chance wants to clear all the data in the table, you can run DB::table('profiles')->truncate(); . All data will be cleared without actually deleting the table.

Displaying the data to the view

In Part 6, we've learned how to fetch the data to the view. We need to the same this time but there's a tiny difference. Because we want to display the profile that belongs to a user, we need to specifically tell Laravel the table name. For example: {{$variableName->tableName->columnName}}

 9
10
11
12
13
14
15
16
17
18
19
20
21
        <div class="col-8">
            <div>
                <h2 class="font-weight-light">{{$user->username}}</h2>
            </div>
            <div class="d-flex pt-4">
                <div class="pr-5"><strong>4</strong> posts</div>
                <div class="pr-5"><strong>165</strong> followers</div>
                <div class="pr-5"><strong>176</strong> following</div>
            </div>
            <div class="pt-3"><strong>{{ $user->profile->title }}</strong></div>
            <div>{{ $user->profile->description }}</div>
            <div><a href="#">{{ $user->profile->url }}</a></div>
        </div>
resources > views > home.blade.php

Save changes and view the site. You can now see the title and description of your profile changed to the value that you inserted.

Alternative way to insert data manually

Our url is currently empty, right? Let's try to run these:

  • $user = User::find(1) - Display the user with the id of 1
  • $user->profile - Display the profile of that user
Notice that we're using $user not $profile? So if you use $profile->url = 'yourwebsite.com'; you definitely will encounter an error because $profile is not declared and you're editing the User table. To insert data to Profile while in the User table, you use $user->profile->url = 'yourwebsite.com'; . After inserting it, you cannot save it with just $user->save(); because that will save the table for User. You would want to save the Profile table because url is in the Profile table. To save the Profile table, simply use push(); . The final command would be $user->push();


Everything is saved! Now open the site and you should see something similar to this.


Helpful links 🔗

  1. https://laravel.io/forum/06-03-2014-how-to-drop-table-contents-with-artisan-tinker

No comments:

Post a Comment