تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Creating Comment Model0:00

Okay, let's start working on the Comment section. Now, this can potentially have a lot of features, but I'm just going to keep it pretty simple to start. For example, we're just going to have replies available on the Idea itself and not on individual comments. So we'll start with the models and migrations and rendering it in the Vue in this video. So let's start with a model, php artisan make:model Comment -a for everything else. Okay, and let's start with the migration. So create comments table.

Okay, and let's start with the migration. So create comments table. And let's start with the actual comment. So I'm going to name it, let's name it body. So table, text, body. Comment would be a better name, but we'll run into this situation where we do comment. And I don't want that. Okay. Actually, this goes above the timestamp. And we're going to have two relationships here.

Actually, this goes above the timestamp. And we're going to have two relationships here. So let's add them. So the first one is the User. So for an ID, it's going to be named the user_id. And that's constrained to the users table. Okay. And the next one is for the Idea. So same thing, but for idea. Okay.

Defining Eloquent Relationships1:22

So same thing, but for Idea. Okay. And that's all we need for now. So let's go ahead and add those relationships. Let's start with the User. So a User has many Comments and a Comment belongs to a User. So let's just copy this one here for ideas, or ideas. And say the same thing, but for comments. Okay, this has many Comment class. And the same for ideas.

Okay, this has many Comment class. And the same for Idea. So we'll just grab this. Go to Idea and paste it in. Put it here. Okay. And for the actual Comment, let's add those relationships. Actually, let me add guarded to an empty array first. Okay. And let's add those.

Building Comment Factory2:12

Okay. And let's add those. So user. So return this belongsTo a User. Okay. And the same for an Idea. So let's just duplicate this and change this to an Idea and this as well. Okay. Now let's work on our CommentFactory. So we have some data and also for testing.

Now let's work on our CommentFactory. So we have some data and also for testing. So for the standard definition, let's do that first. So just like in our migration, we have a user_id and that can just use the UserFactory to generate one User. Okay. And the same for an Idea. So let's add an Idea, change this to an Idea to import those. And Idea. Okay.

And Idea. Okay. And we need a body here. So I'll say body and let's use faker here. This faker. Let's make a paragraph with five sentences. Okay. Sorry. That should be a comma. And just like in our Idea, we have a different state for our databaseSeeder, and I believe

That should be a comma. And just like in our Idea, we have a different state for our database Seeder, and I believe I named it existing. Sorry. Not Idea. IdeaFactory. So here's the standard definition, and here's the existing definition. So let me grab this. Let's paste that in. Same.

Seeding Comments Data3:45

Let's paste that in. Same. It's the same, but we only need the userId here. And in this case, I'm going to leave it here because we have 20 users in our database cedar here. Okay. So now let's generate some comments for each of the ideas after we do this. Let's say generate comments for ideas. So at this point, we should have all of our ideas. So let's go ahead and loop over those.

So at this point, we should have all of our ideas. So let's go ahead and loop over those. So let's say foreach $ideas as $idea. Okay. And let's just generate. Oops. Let's just generate some comments for each of those ideas so we can use that factory. So say CommentFactory::times(5)->create([ 'idea_id' => $idea->id ]); Let's use that state.

Say five comments for each idea. Let's use that state. So it's constrained to the number of users we have in this database seed. So existing is the name of the state we just made to create. And we do want to use the idea in each loop here. So ideaId is the idea ID. Okay. So let's import Comment. And let's try php artisan migrate:fresh --seed. Okay.

And let's try php artisan migrate --fresh --seed. Okay. Looks like it worked. Let's check our database here should be a new comments section here to refresh this. There it is. And we do have 500 which makes sense because we have 100 ideas and I generated five comments for each idea. And it looks like the users are constrained to those 20 users. So it is working. Cool.

Rendering Comments in Livewire5:38

So it is working. Cool. Okay. So now let's work on rendering the Comment in our browser here. So we want to render it in here. So I'm gonna do the same thing I did for the Ideas and that's have two components. So one component is called for the ideas Index and that's responsible for fetching the ideas. And then we have another component responsible for rendering the individual Idea. So let's do that.

And then we have another component responsible for rendering the individual Idea. So let's do that. So let's go in here. Let's make two Livewire components. So say php artisan make:livewire it's called the first one that fetches the IdeaComments. And then the second one is called IdeaComment for one of them. Okay. So let's start with the IdeaComments. So let's go into that.

So let's start with the Idea comments. So let's go into that. This will accept the comments but that comes from the Idea. So I guess I'll just accept the Idea. So same as the other components. So public Idea and second amount of method here takes in the idea. Okay. And let's assign it. This idea is idea again you don't have to do this. You can just declare the variable up here and it should do it automatically.

This idea is Idea again you don't have to do this. You can just declare the variable up here and it should do it automatically. But since I already have it this way I'm just going to keep it consistent. Okay. So like I said we want to pass in the comments here so we can do that in here. So let's say comments is this Idea comments. Okay. That should be good. So now in our show Blade where we're rendering placeholder comments let's replace it with our new component here.

So now in our show Blade where we're rendering placeholder comments let's replace it with our new component here. So that would be this in the browser which is all dummy data for now or not even dummy data just hard coded or one hard coded Idea I mean. So that would be where is it right here I believe somewhere. Actually I think I have it in the IdeaShow component actually no it's right here in the show Blade. So I have this foreach that just loops over this one div with the comments. So let's just grab this entire thing which is the comments container. So let's just grab that and say actually it's put it above these models and notifications.

So let's just grab this entire thing which is the comments container. So let's just grab that and say actually it's put it above these models and notifications. So right underneath the Idea say Livewire Idea Comments and let's pass in the idea. Okay. See if this renders. Actually we have to add what I just cut into our Idea Comments and paste that in and re-indent. Okay so let's see if it still renders should be the same and it is. So now we should have access to that comments variable. So let's work on that. So now we can loop over those comments and render out a single comment.

So let's work on that. So now we can loop over those comments and render out a single comment. So say for each comments is the variable we're passing in with all of our comments for this Idea say comments as comment and we'll make a new Livewire component here say Livewire or we have one already IdeaComment. And for this we're going to accept a key and that will be the comment ID. Okay. And the comment is a comment and that should be good. So let's go ahead and go to that component. So IdeaComment and just take some code from our ideaComments.

So let's go ahead and go to that component. So IdeaComment and just take some code from our IdeaComment. The same thing but we're accepting a Comment now. So we'll just grab this and paste that in here. So now it's a Comment. Okay. Changes to a Comment import that should be that one. And this is now Comment. Okay. So let's save that.

Okay. So let's save that. And now we can go back to our component here. So Idea comments and we can get rid of this foreach. And we can grab this entire comment container and put it in our new component. Okay. And what's this one for? Oh, this is for the case when it's an admin content. So we'll worry about that later. Okay.

So we'll worry about that later. Okay. So there should be good. Save that. Let's go back to our Idea Comment and let's go ahead and paste this in. Okay. Let's re-indent. And now if I did this correctly, it should render five Comments because we have five in the database for each Idea and there is five. So it is working.

in the database for each Idea and there is five. So it is working. So let's go ahead and replace this data with the actual data for the Comment. So let me get rid of this. We don't need this commented code. So this is the Comment itself. So I named that commentBody. This is the timestamp and we can use Carbon here commentCreatedAt and let's say, sorry, it's created_at diffForHumans(). Okay.

it's created underscore at diff for humans. Okay. This is the username. So let's say commentUserName. Okay. And then we have the avatar. So this I believe commentUser and we have that method for our avatar called getAvatar. Okay. So I believe that's everything. Let's go ahead and refresh this page.

So I believe that's everything. Let's go ahead and refresh this page. And it looks like it does work. Cool. Looks like there's some extra margin that I don't need here. So let's see what's going on there. So yeah, there's an empty three here, which I don't need. So let's get rid of that. So it's called right there. So let's get rid of that.

So it's called right there. So let's get rid of that. Okay. Okay. Now let's work on the case where there's no comments. So for example, let's just make a new comment here. So let me just log in real quick and let's make a new Idea here, which will have no comments. And I just want to have a placeholder there. So let's go ahead and add that comment. And this one will have no comments.

So let's go ahead and add that Comment. And this one will have no comments. So just like when there's no Ideas, I want a placeholder here. So I don't have a design for this yet. So I'm just going to take what we have for the ideas. So if you don't remember, if I just search for gibberish, we have a placeholder image here. So we'll do the same thing. So I believe that's in ideas/index. There should be a foreach else in here.

So I believe that's in ideas index. There should be a foreach in here. Yeah. So loop over them if they exist, but if not, then we have this placeholder, which we'll steal. Let's do the same for idea comments. Let's do the same thing. So let's try foreach. Let's end the foreach. And let's say empty.

Let's go back to that new Idea. Sorry, let's get rid of this. And that looks good to me. Actually, no, we have this line to the left because we have a comments container and I'm using the :before pseudo selector. So I don't want that to appear. So we can't use a for else here. We have to use an if. So let me grab this again and let's undo everything here. Leave it as a foreach.

So let me grab this again and let's undo everything here. Leave it as a foreach. But now we just have to check if there are comments on this entire container. So let me just wrap everything in a new div, because I think we need one new div for Livewire components. So say div. And now we can check if there are comments. And if there are, go ahead and render the entire container. Let's do that. So if comments is not empty, then go ahead and render this entire thing.

Let's do that. So if comments is not empty, then go ahead and render this entire thing. So let me just move this up into the if block. But if not, then go ahead and render that container with the image, the placeholder image. So let me paste that in. And this should work as well. Okay. But the line here is now gone. So let's just make sure that the comments still render for the other ideas.

Updating Comment Count15:19

But the line here is now gone. So let's just make sure that the comments still render for the other ideas. That does. Cool. Okay. Now let's update the comments count. So this is a separate component. So this is our IdeaShow component. So let's go ahead and add it in there. So it's IdeaShow.

So let's go ahead and add it in there. So it's Idea show. And we have this. So like I said, this is a separate component. So we don't have the comments in here. So we can load them in like this and count them. But let's take a look at our queries and models here. So let me open up the bug bar here. And we have 15 queries and 20 models. So let's see how many we get now after we added that code.

And we have 15 queries and 20 models. So let's see how many we get now after we added that code. So I did save it. Let's refresh. And it's still 15 and 20 right now, because at this point, we are loading in every single model or sorry, every single comment. So we'll leave it for now. But we may have to switch this later on when we do pagination for comments. So let me just add the word comments in here. Okay.

So let me just add the word comments in here. Okay. And that looks good. We also have to change it on the index page here. So let's go ahead and update that. So this will be on the Idea index page. Okay. So let's do the same thing. So let's just grab that. Okay.

So let's just grab that. Okay. And it's pasted that in. So Idea comments count. But again, keep an eye on the number of queries and models. So we have 9 and 42. And then we have 19 and 87. So it looks like we do have an n plus 1 issue here. So we can fix that using eager loading. So we do the same thing for votes here.

So we can fix that using eager loading. So we do the same thing for votes here. So let's go to our ideas index. And down here, like I said, we're doing the same thing for our votes using the withCount method. We can do the same thing for comments. But now we also have to pass in the comments count like we did for the votes. So for our ideas index. Actually, no, I don't think we have to pass that in because it should be on the Idea directly. So let me just dump the idea here.

Actually, no, I don't think we have to pass that in because it should be on the Idea directly. So let me just dump the idea here. And we should see a comments count. So let's refresh. Sorry, the ideas. Okay. And yeah, you could see a comments count here. So zero for the first one. And I scroll down more. The next one should be five.

And I scroll down more. The next one should be five. So yeah, you can see five on the rest of them. Okay, so we can just grab it from the Idea directly. So let's get rid of this. Let's go to our ideas/index, or sorry, idea/index. And let's change this to idea.commentsCount. Okay. And now you can see the n plus one issue should be solved. So actually, let me put that back for a second, just so we can get the numbers again.

And now you can see the n plus one issue should be solved. So actually, let me put that back for a second, just so we can get the numbers again. So 1987. But if I change it to this, it should be less. And we're back down to nine and 42. So there's one more case I want to handle, and that's when we delete an Idea with comments. So this is going to fail now for the same reason it failed when we had votes initially. So let's go ahead and try to delete this Comment, and you'll see what I mean. delete. And we do get this integrity constraint violation because the Idea we're trying to delete is

Delete. And we do get this integrity constraint violation because the Idea we're trying to delete is referenced on another table. So we have to delete those first. So let's go ahead and do that. Actually, let's update our tests first. So we can go to DeleteIdeaTest, and we have a similar one here for the Votes. So this one. So it's basically the same thing, but for Comments. So let's duplicate this.

So it's basically the same thing, but for comments. So let's duplicate this. Let's say deleting an Idea with comments works when User has authorization. So we don't care about votes anymore, but we do care about comments. So let's go ahead and just add one here. So CommentFactory. And let's just add create. And the userId is actually doesn't matter who created it. So let's do CommentFactory::create import Comment. And we should get that same error because we have a Comment on it.

So let's do CommentFactory::create import Comment. And we should get that same error because we have a comment on it. Okay. And we do get an error, but we don't get that database error. Let's see if I remove this, will we get that error? It is passing. But why? Oh, sorry. We do have to add an Idea here. That has to be the Idea we're looking at, obviously.

We do have to add an Idea here. That has to be the Idea we're looking at, obviously. So ideaId is ideaId. And now this should result in that error. And it does, I think. Let's scroll up. Yeah. So we do get that database error. So let me put this back and it should still fail. This is the correct assertion.

So let me put this back and it should still fail. This is the correct assertion. We want to make sure after we delete, we have zero Ideas. So let's go ahead and fix that in our actual code. So that should be in deleteIdea. So we're doing the same thing, but we want to delete comments. So this should be comment and import Comment. And that should be good. So now our test should pass. And it does.

So now our test should pass. And it does. So let's go ahead and try it in the browser. Refresh. And this has comments. But if I delete it, actually, let's take a look at our comments database here, or comments table. We have 500. And after I delete it, it should be 495. Delete.

And sorry about this merge I had to do. I undid a commit, and I already had it on the GitHub repo. So I had to do a merge conflict fix. But this is episode 48, git add, git commit episode 48. Let's say comment, migration, and models, or model.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟