DARK MODE 

Posted on Friday, June 3, 2022 by

Create Instagram Clone with Laravel (Part 12): Editing Profile Image and Automatically Create A Profile Using Model Events

In this post, I covered from minute 2:54:50 until 3:12:56 of this video.

In this part, we are going to learn on how to update/edit the profile image. 

Editing the profile image
The way we're getting the image and store it in a folder is the same as we done for the post controller when user uploaded an image to a post, with a minor change to the stored location. We will store the profile image in profile folder instead of posts. Another thing is, when we want to pass the data, instead of passing it as a normal array, we will use a php function called array_merge. This function takes any number of array and appends them together. At line 41 and 42 of the code below, the $data array does have a key of image but the second array ['image' => $imagePath] overrides that image.

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
    public function update(User $user)
    {
        $this->authorize('update', $user->profile);

        $data = request()->validate([
            'title' => '',
            'description' => '',
            'url' => 'url',
            'image' => ''
        ]);

        if (request('image')) {
            $imagePath = request('image')->store('profile', 'public');

            $image = Image::make(public_path("storage/{$imagePath}"))->fit(1000, 1000);
            $image->save();
        }

        auth()->user()->profile->update(array_merge(
            $data,
            ['image' => $imagePath]
        ));

        return redirect("/profile/{$user->id}");
    }
app > Http > Controllers > ProfilesController.php

To see what the array_merge do clearly, let's try die and dump it.

dd($data)

array_merge

This should be ready to go. However, if we look at profiles table, we don't really have anything for image so we're going to add it. If not, we definitely will run into error that says the image table doesn't exist.

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

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

Now that we have changed the Schema, we need to remake our database. Always remember to remake database every time you can change anything for migrations! Let's run php artisan migrate:fresh. This will erase everything so we're going to start from scratch again.



Create A Profile Using Model Events
Let's go ahead an register. After registered, when you try to open your profile, you will get an error. This error is because when we creating a user, we are not creating a profile for them. There is no record of user in the profiles table. So as part of our registration, we really need to create kind of a blank profile for user so they can start using it and edit it. 



There are several ways to overcome this. What we're going to do is hooking up an event in the user model. Something that says, "Hey, I am creating a new user, is there anything else that I should do?". 

There is this method called boot. This boot method is what gets called when we are booting up the model. In the method, we hook a created event. Please refer to Events in the documentation. There are creating, createdupdating, updated and many others. The different between '-ing' and '-ed' is, '-ing' gets called before it actually creates the record and database, '-ed' is after it's done. In our case, we're using created, meaning that, after the record for user has been created, we then create the profile for that user. We can just create an empty profile for that user with $user->profile()->create() but let's say if we want to add a default value for some of the table, we can write it like line 51 - 53. The lines mean that we set the default value for user's title the same as their username.
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    protected static function boot()
    {
        parent::boot();


        static::created(function ($user) {
            $user->profile()->create([
                'title' => $user->username
            ]);
        });
    }
app > models > User.php

Let's try registering a new user again! It should be working and look like this:



Displaying the profile image
Right now, our profile image is still hardcoded. We need to pull the image and display it properly.
6
7
8
        <div class="col-4 d-flex align-items-center justify-content-center">
            <img src="/storage/{{ $user->profile->image }}" class="rounded-circle w-100" style="border: 1px solid #e4e3e1">
        </div>
resources > views > profiles > index.blade.php

By default, the profile image is empty so you will get a broken image until you upload a new image in edit profile page. We will fix this later.

Adjusting the view for individual post page
Now for the individual post page, again, we need to pull the image from our table, and style the page to make it look as closely as possible to Instagram.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-8">
            <img src="/storage/{{ $post->image }}" class="w-100">
        </div>
        <div class="col-4">
            <div class="d-flex align-items-center">
                <img src="/storage/{{ $post->user->profile->image }}" class="rounded-circle mr-3" style="width:40px;border: 1px solid #e4e3e1">
                <a href="/profile/{{ $post->user->id }}" class="font-weight-bold text-dark">{{ $post->user->username }}</a>
                <a href="#" class="font-weight-bold pl-3">Follow</a>
            </div>
            <hr>
            <p>
                <a href="/profile/{{ $post->user->id }}" class="font-weight-bold text-dark">{{ $post->user->username }}</a>
            
                <span>{{ $post->caption }}</span>
            </p>
        </div>
    </div>
</div>
@endsection
resources > views > profiles > show.blade.php

It's finally looking more like Instagram post now.



That's all for now. In the next part, we will learn on how to add a default profile image and make it possible that a user doesn't need to upload profile image every single time they want to edit something in their profile.








No comments:

Post a Comment