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

Planning Voting Feature0:00

Now, we're making pretty good progress, but one thing we haven't even touched on yet is the ability to vote on particular community links. And that way, if 50 people vote on this link and 20 people vote on that link, well, we can sort them, and it gives you better feedback for which articles are really good. For example, at Laracast, yeah, you can see we offer this very thing here. So this one has 108, which means it's probably a very good tutorial. And of course, you can vote on them, you can unvote them, all that stuff. Okay, so it's going to take maybe two or three videos to go through all of that process. There's a number of steps, but we'll get started on it in this lesson. Now, it sounds like we need a table to store the user_id as well as the community_link that they are voting on. So kind of a traditional pivot table. php artisan make:migration create_community_links_votes. Should it be Community,

Creating Votes Migration0:44

as the community link that they are voting on. So kind of a traditional pivot table. php artisan make:migration create_community_link_votes. Should it be Community, Link, Votes or Community, Links, and then the votes for that? I don't know. Maybe naming things is hard. Let's do Community, Links, Votes table. Like so. Okay, so if we switch over to that file, we can do this in a number of ways. We could have a primary key that's not the ID, but instead the primary key would be, for example, the userID and the communityLinkVotesID. That would be an option. And then you don't do this at all. That really wouldn't be a problem and it's fairly common. Another option is the more traditional, just keep the ID and then you set your userID, which is an index, and then the communityLinkID, which is also an index. For indexing, that can be kind of confusing for folks.

just keep the id and then you set your userId, which is an index, and then the communityLinkId, which is also an index. For indexing, that can be kind of confusing for folks. It's actually a lot more complicated than you'd think. However, as a general rule of thumb, if you intend to search a table based upon a particular column, then you might want to index it. So like if you have a big comments table, well, you might want to frequently fetch all comments for a post. Well, in that case, you would make the postId an index. But yeah, it's actually pretty complicated stuff. So let's go ahead and migrate our database and we can get started. Now, one thing I think we'll want, let's go to Community, Link. We'll need to find all of the votes for a particular Community, Link. So I'm assuming I can do something like this, link and then give me a collection of all of the people who voted for

Adding Vote Model2:15

We'll need to find all of the votes for a particular Community, Link. So I'm assuming I can do something like this, link and then give me a collection of all of the people who voted for it. So votes would either be a collection of Users, or maybe it's just a collection of that actual table. And maybe that would be fine. So if we wanted to do that, maybe it would take the form of something like this, a Community, Link has many votes. And why don't we do this, let's give it its own model. And this is generally a good practice, especially if there's behavior that's associated with the pivot table. So if there's no behavior, then you can probably get away with not creating a model for the pivot table. But if you find more behavior you want to add to it, that's usually when it's a good idea to give the pivot table its own model. So maybe we'll call it CommunityLinkVote. And let's see, the foreign key would be community_link_id is what we called it.

it's a good idea to give the pivot table its own model. So maybe we'll call it CommunityLinkVote. And let's see, the foreign key would be community_link_id is what we called it. Okay, I'm going to create that class. I'll keep it in the app directory. And then I'm going to have it extend, of course, Laravel's Model class. And why don't we, let's be explicit about the table name, community_links_votes. Okay, so now why don't we just try one out really quick, php artisan tinker. We're going to say app\CommunityLinkVote. And I'm going to do forceCreate since I don't have any mass assignment settings yet. The userId will be our main JohnDoe guy, and I happen to know that's 12. And then the community_link_id that he's going to vote for will be, how about 44? Okay, so we have one new record, and we have our first relationship. The user with an ID of 12 has voted for the CommunityLink with an ID of 44.

Testing Relationships in Tinker3:50

going to vote for will be, how about 44? Okay, so we have one new record, and we have our first relationship. The User with an ID of 12 has voted for the Community, Link with an ID of 44. So now I think we could do this. Community, Link, find the ID by 44. And if I now say Link, Vote, it should load the relationship, but it doesn't. And I'm guessing that's because we're not returning. So if we go back to Community, Link, and we find it, yep, totally forgot to return it. So let's try that one more time. Fetch our link, and then give me the votes associated with it, and we do get a collection. So now you can do things like this. This votes, pluck the userId, and that'll give us a collection of all users who have liked that particular link. Or you can always call all to give us just a simple array. We have a lot of flexibility now. Further, if we go back to phpstorm,

of all User who have liked that particular link. Or you can always call all to give us just a simple array. We have a lot of flexibility now. Further, if we go back to PHPStorm, let's go ahead and add our doc blocks and be good citizens. A community link may have many Votes. Anyways, go to our controller. I could now say, once again, it's getting a little more complicated, like I keep saying. And eventually, we're going to have to add a join, and it'll get even more complicated, and we'll have to extract it. Let's eager load the votes. And so now I can say Links. And if we go to Chrome and give this a refresh, let's see what we got here. Okay, the very first community link, there's the attributes. And if we take a look at the relationship, it's a collection consisting of one item, which is right here. So yeah, now we're eager loading that rather than potentially hitting it.

Showing Votes in View5:26

And if we take a look at the relationship, it's a collection consisting of one item, which is right here. So yeah, now we're eager loading that rather than potentially hitting it multiple times with DB queries. Another way, of course, is just to be explicit. So give me the votes where the user_id equals the authenticated user, and then pluck the community_link, and then pluck the community_link_id, and save that to votes, and then you pass that through. That would be another way to do it if you didn't want to eager load. But if we do eager load it in this way, we save one more variable that has to be sent through to the view. So like if we go to our index view, we go to our list. Now we could do something like this, maybe at the top to start. If the user is signed in, and link, we're going to change this in a minute, but link->votes contains where the user_id equals the authenticated user, then we could say plus one. Let's see,

If the user is signed in, and link, we're going to change this in a minute, but linkVotes contains where the userId equals the authenticated user, then we could say plus one. Let's see, we did that quick, but let's see if that works. Yeah, there we go. So we had our JohnDoe character vote for this particular article, so it shows up. But for these, he hasn't voted on those yet. We could set it up for him though. Let's go back a few clicks. Let's have him create another one where the communityLink is 11. That's one that's in the database. So now if we refresh, we should show that one there. Okay, so what happened here? Well, we fetched the relationship, and that's now a collection, right? linkVotes is a collection. So we're saying, I want to determine if that collection contains an item where the userId within it is equal to the current user. And if so, that means the authenticated user liked this post. But notice,

User Voting API Methods7:02

I want to determine if that collection contains an item where the user ID within it is equal to the current user. And if so, that means the authenticated user liked this post. But notice, I did have to break it down and explain to you. What if we could write this another way by saying, if you're signed in, and the authenticated user voted for this link, then continue on. Well, notice this time, I don't have to do anything special to explain to you what's going on here. If you do need to dig into it and figure out the inner workings, you can. But on the surface level, this is far more descriptive. Back to Chrome, refresh, not going to work, right? There is no votedFor method. All right. User voted for the given community link. And now here is where we can add that exact same logic. LinkVotes contains an item where the user ID is equal to this user. And now if I come back, it should work. And it

community link. And now here is where we can add that exact same logic. LinkVotes contains a item where the userId is equal to this user. And now if I come back, it should work. And it does. Great. So we're going to finish up. We still have to turn this into a button and submit an AJAX request. But we just kind of wanted to get the initial work done in this video. But I would like to set up one other thing. If I bring back php artisan tinker, what is the API like for actually voting for a Link? So for example, you could say User::voteFor(link); That would be an option. It's going to fail because I don't have a user. But that's fine. We're just focused on the syntax here. You could have a link, and then you could say votedBy the user. You know, you can prepare this however you want to. What I think you'll find is that often you want to attach it to the User model, which is also kind of a danger at the same time. So it always feels natural to have the

this however you want to. What I think you'll find is that often you want to attach it to the User model, which is also kind of a danger at the same time. So it always feels natural to have the User do something because that's really what's taking place. But then as a project grows, your User model is going to become that god object that we're all afraid of. So you want to be careful about just throwing every possible thing onto the User. Do it when it makes most sense. But sometimes you might want to consider something else. And that's when you would watch the Monstrous Code series here at Laracasts. And I think you'll get some ideas. But for now, for this little project, I think that would be great for us. So let's see. We have votedFor, so let's add a new one called voteFor. Once again, we'll accept the link. And then we could say linkVotes create a new one where the user_id is equal to this User. And we can reference

so let's add a new one called Vote for. Once again, we'll accept the link. And then we could say link->votes()->create() a new one where the user_id is equal to $this->user. And we can reference the relationship that way. Now, I think this is going to fail right now. So if we try it, we'll grab a User and then grab a Link. Grab the first one. Okay. And then we'll say $user->voteFor($link). But I think it's going to fail. Yeah, we're going to get a mass assignment exception. So we need to take care of this on the CommunityLinkVote end. The fillable fields will be the user_id, as well as the community_link_id. Okay, let's try it again. Refresh everything. Find a User, find a Link, have the User vote for the Link. And now we have recorded a new row within that pivot table. And I think, yeah, this API will work just fine for our needs. Okay, still quite a bit more to do. So I will see you in the next episode.

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