In this post, I covered from minute 3:12:56 until 3:33:55 of this video.
Displaying default profile image
First upload the default photo to your profile. Then, copy the link because
we just wanna get the filename. After that, we create a new method in the
profiles model. In this new method. we say that if the image is set, then
we're going to return
/storage/
and then that image. Otherwise, let's
return the default image which in my
case, profile/MdCtU1BFI5rfrDfViQ6UeoYb22wcKkg0n0ClxFYU.jpg
.
14 15 16 17 18 |
public function profileImage() { $imagePath = ($this->image) ? $this->image : 'profile/MdCtU1BFI5rfrDfViQ6UeoYb22wcKkg0n0ClxFYU.jpg'; return '/storage/' . $imagePath; } |
app > Models > Profile.php
6 7 8 |
<div class="col-4 d-flex align-items-center justify-content-center">
<img src="{{ $user->profile->profileImage() }}" class="rounded-circle w-50" style="border: 1px solid #e4e3e1">
</div>
|
resources > views > profiles > index.blade.php
14 |
<img src="{{ $post->user->profile->profileImage() }}" class="rounded-circle mr-3" style="width:40px;border: 1px solid #e4e3e1">
|
resources > views > profiles > show.blade.php
Solving problem with empty image field in edit profile form
When we try to save our profile in the edit page without uploading any profile
image, we will get
Undefined variable: imagePath variable
. This is because the
way we wrote our code before is that we assuming that there's always going to
be an image path. In real world situation, the image path may not be set. And
if it's not set, it just means that there is no image in the request. But what
we've done in the code so far is still trying to insert that image path to the
profile. Hence, it return an error.
To fix that, we extract the image path to a variable and call the variable
$imageArray
after we saved the image. Then. in the array_merge
function, we're
going to say that if the $imageArray
is not set, then let's default it to an
empty array, []
. An empty array will not override anything in our $data
. To
sum it up, we're setting an $imageArray
that is going to contain the image,
but this is only happening if there is an image in the request. Otherwise, the
only thing we're going to pass in is an empty array.
33 34 35 36 37 38 39 40 41 42 43 44 |
if (request('image')) { $imagePath = request('image')->store('profile', 'public'); $image = Image::make(public_path("storage/{$imagePath}"))->fit(1000, 1000); $image->save(); $imageArray = ['image' => $imagePath]; } auth()->user()->profile->update(array_merge( $data, $imageArray ?? [] )); |
apps > Http > Controllers > ProfilesController.php
Now you can try it! You should be able to save your profile without uploading
any profile image, and your current profile image wouldn't be overwritten.
Creating follow button - UI
Let's start with the UI for the profile.
11 12 13 14 |
<div class="d-flex align-items-start pb-2">
<h3 class="font-weight-light mr-3">{{ $user->username }}</h3>
<button class="btn btn-primary btn btn-primary btn-sm pl-4 pr-4 ml-3">Follow</button>
</div>
|
resources > views > profiles > index.blade.php
When we click the button, we don't want the entire page to be loaded again,
don't we? This can be achieve by converting the button to Vue component. As
you already know, Vue is a JavaScript library. Laravel comes with a working component named ExampleComponent.vue in the
resources > js >
components
and it is registered in the app.js. Let's rename
ExampleComponent.vue to FollowButton.vue
, and change the name in app.js also.
22 |
Vue.component('follow-button', require('./components/FollowButton.vue').default); |
resources > js > app.js
We're not gonna learn deeply about Vue because this is a Laravel course. But
keep in mind that the most important thing about Vue is
everything needs to be wrapped in a single div tag inside
template tag. It must be one. You cannot have two div because then it will
tell you that there is no root div. What we need to do next is copy the follow
button code that we done in index.blade.php, paste it inside the component.
After that, change the follow button code in index.blade.php to
follow-button
tag as
shown below.
1 2 3 4 5 |
<template>
<div>
<button class="btn btn-primary btn btn-primary btn-sm pl-4 pr-4 ml-3">Follow</button>
</div>
</template>
|
resources > js > app.js
11 12 13 14 |
<div class="d-flex align-items-start pb-2">
<h3 class="font-weight-light mr-3">{{ $user->username }}</h3>
<follow-button></follow-button>
</div>
|
resources >views > profiles > index.blade.php
Now, we need to run
npm run dev
. However, run dev
is what we would use if we
want to run just one time. If we run npm run watch
, it will continue to watch
all of our files so whenever there's a change, it would automatically compile
all of our code again. This is what we should use during development.
If you open the profile page, you won't see any difference at all.
Creating follow button - action
Next we want to do is of course, create the action for the button. We need to
reach out to the server and ask it to do something when we click the button.
Before we do the reach out the server part, let's try making the button to do
something. Fairly easy.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<template> <div> <button class="btn btn-primary btn btn-primary btn-sm pl-4 pr-4 ml-3" @click="followUser">Follow</button> </div> </template> <script> export default { mounted() { console.log('Component mounted.') }, methods: { followUser() { alert('inside'); } } } </script> |
resources > js > app.js
If you click the button, an alert should should be popped out.
Now, because we want to follow a user, we need to get that user id and pass it
to the method in component. To do that, we can just pass the id through the
follow-button
.
13 |
<follow-button user-id="{{ $user->id }}"></follow-button>
|
resources >views > profiles > index.blade.php
Then, to get the id, we write:
8 9 20 |
export default {
props: ['userId'],
...
}
|
resources > js > app.js
To reach out to the server, we can do that with Axios that comes with Laravel.
Axios is a library that allows you to make API call extremely easy. So inside
the followUser method, we need to say, "Axios, make a POST request to an
endpoint, and then display the data".
19 19 20 21 22 23 |
followUser() {
axios.post('/follow/' + this.userId)
.then(response => {
alert(response.data);
});
}
|
resources > js > app.js
We then need to create a route for the new axios call.
20 21 22 |
Auth::routes();
Route::post('/follow/{user}', [App\Http\Controllers\FollowsController::class, 'store']);
|
routes > web.php
Next, create the controller for Follows.
php artisan make:controller FollowsController
And add a new store method. For now, let's just return the username.
8 9 10 11 12 13 14 |
class FollowsController extends Controller
{
public function store(User $user)
{
return $user->username;
}
}
|
app > Http > Controllers > FollowsController.php
The button should be able to return the user's username successfully.
Creating follow button - connect Profile to User
Now, we are gonna explore the many to many relationship. Up to this point, we
talked about one-to-one and one-to-many relationship, but now, many-to-many.
Why? Because a profile can have many followers and a user can follow many
profiles. In the previous relationship, we just add a foreign key to the
table. But in many-to-many, we need to create a pivot table. A pivot table is a table that holds the ID of the two related models. If
I'm right, the ERD is this.
For this one, we don't need a model, we only need the migration. To make this
migration, you must follow a naming convention. For the naming convention, we
first must identify what are the two models that we want to connect. We want
to connect Profile and User. In Laravel, we need to put them in alphabetical
order. So Profile first because P comes first and U comes later. We also need
to write them in all lowercase character and put underscore in between the
names. We then got
profile_user
- this will be the table name. And for our
migration name, we use creates_profile_user_pivot_table
. The final command
would be
php artisan make:migration creates_profile_user_pivot_table --create
profile_user
Let's open the newly created migration file and add two fields which are
profile_id
and user_id
.
16 17 18 19 20 21 |
Schema::create('profile_user', function (Blueprint $table) {
$table->id();
$table->foreignId('profile_id');
$table->foreignId('user_id');
$table->timestamps();
});
|
database > migrations > Controllers > 2022_06_06_055949_creates_profile_user_pivot_table.php
Lastly, migrate the table
php artisan migrate
We now done with connecting the profile and user model. However, there is
still more needs to be done for the follow button to fully functioning like
Instagram. But I need to stop right here because the post is getting too long.
We continue completing the button in the next part!
Can u pls do for next parts pls?
ReplyDelete