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

Load Categories Dropdown0:00

Okay, let's go ahead and work on actually editing the Idea. So the first thing I want to do here is grab the categories from the backend and populate this drop down here. So let's start with that. So I'm in my component here, let's go ahead and grab the categories. So let's say categories is categoryAll. Okay, let's make sure to import Category. And in our Blade view, in the categories, where is it? CategoryOne, right here, we can foreach over this and say categories as category. Now we can loop over this, this will be categoryName.

Category one, right here, we can foreach over this and say categories as category. Now we can loop over this, this will be categoryName. And this will be categoryId. Okay, let's see if that works. And edit, looks like it does. So if you look at the debug bar, you'll see that we're actually performing duplicate queries here. It says two of them are duplicated. And that's because we're doing it here in the edit, like you just saw, and we're also doing it here in the add an idea form.

Avoid Duplicate Queries1:18

And that's because we're doing it here in the edit, like you just saw, and we're also doing it here in the add an idea form. Now in this case, these queries execute really quickly, we look at the debug bar, there should be some stats on that. You can see one here that takes 400 microseconds, and 300 for the other one. So less than one millisecond for both queries. Now if you wanted to avoid duplication, or if you had to perform this query even more times, or if this query were expensive, then the best solution would be to execute this query once globally somewhere and then pass it into any component that needs it. So to do that, you can use View Composers, which you can see here in the docs.

query once globally somewhere and then pass it into any component that needs it. So to do that, you can use View Composers, which you can see here in the docs. And let me just show you how you would do that. I'm not going to do it here. But you would go into your AppServiceProvider. And I have it on my clipboard, it just do something like this. So View Composer, pass in the views you want it to be available, in this case, the layouts.app. So this will be basically every view. And then you'll have access to this $categories variable in all your views.

So this will be basically every view. And then you'll have access to this categories variable in all your views. Now since we're using Livewire, we'd have to pass this variable into the components. So for me, it's not worth it, because I'm just doing it twice. So let me just undo that. And I think on the index page, I'm actually doing it twice as well. So once here, and once here as well. So if you look at the queries, you'll see some duplicates as well. And somewhere down here, there's one there, and another one up here. So like I said, if this duplication happened maybe four or five times, then I would consider

Prefill Edit Form2:53

And somewhere down here, there's one there, and another one up here. So like I said, if this duplication happened maybe four or five times, then I would consider moving it to a View Composer, or if the query were more expensive in terms of how long it took to execute. Okay, back to our Idea here, our editIdea. Next thing I want to do is populate this with the actual details of the Idea. So here is where we're using the Livewire component, and we have to pass in the idea. So I'm just going to grab it from the idea show, and we'll pass that through like this. And now we can go to our component and accept that. So let's say public $idea, and let's use the mount method.

And now we can go to our component and accept that. So let's say public $idea, and let's use the mount method. Oops, I keep doing that instead of my snippet. mount($idea), $idea, and let's assign that $this->idea equals $idea. Okay, just make sure to import that. And I believe since I copied it from the CreateIdea form, the wire:model is set. Yeah, they are. So we have a title, a category, and a description. So let's go ahead and add those fields as well. So I'm going to grab it from the CreateIdea component.

So let's go ahead and add those fields as well. So I'm going to grab it from the CreateIdea component. So let's just grab these title, category, and description. EditIdea. Okay, we don't need the default here. And let's set them as well. So let's go to our editIdea, and let's say title equals ideaTitle. category is ideaCategoryId. And let's change this to category. And this one description is ideaDescription.

And let's change this to category. And this one description is Idea description. Okay. So I believe you can bind the actual Idea to the model itself. So in editIdea, you can do something like ideaTitle or ideaTitle. I'm not sure exactly, but I'm just going to do it this way. So let's see if it actually populates the Idea when we open this model up. And it does. So we have the title, the correct category, and the correct description. I'm going to change this submitText to say update instead.

Implement Idea Updates5:32

So we have the title, the correct category, and the correct description. I'm going to change this submit text to say update instead. So let's look for submit here, and let's change it to update. Let's also change the form handler. So let's look for the form here. And instead of createIdea, let's say updateIdea, and let's make a method for updating the idea. So let's say updateIdea. And first, we'd have to do some authorization, which we'll do later on, or maybe in the next video.

And first, we'd have to do some authorization, which we'll do later on, or maybe in the next video. Then we'd have to do some validation, which we'll do after I get the updating working. But let's focus on updating first. So you can set the fields directly on the Idea. So for example, this idea title equals this title. And then you can save the idea, or you can do it in a batch using the update method. So let's do it that way. So this idea update, and we are updating the title, which will be this title, the description or the category_id first, this category, and the description, which will be this description.

So this Idea update, and we are updating the title, which will be this title, the description or the category_id first, this category, and the description, which will be this description. So let's see if this actually updates the Idea. So nothing's going to happen in the UI, but we can check the database to see if it worked. So let's refresh. Let's go ahead and update, or make a change here, say updated, say category 1. And let's just change this to update it. And let's see if this works. I'm going to hit update. Okay, let's check our database here.

I'm going to hit update. Okay, let's check our database here. So it should be this one here, I'm going to refresh. And it looks like it did update the category change, the title changed, and the description changed too. So first, let's close the modal after it updates. So this is the same as the setStatus. So we're going to emit an event. So if you don't remember, setStatus, we are emitting this event. So let's just grab this actually, close this, and in our setStatus component, we are listening.

So if you don't remember, set status, we are emitting this event. So let's just grab this actually, close this, and in our setStatus component, we are listening for that event using Alpine, and then closing it. So we can do the same thing. So let's go back to editIdea. Let's emit that event. Let's call it ideaWasUpdated, okay, ideaWasUpdated, and then we can grab this code for the Alpine component to listen for that event, and then close the modal. So this would go on the editIdea Alpine component. So anywhere up here, I'll put it right after this.

So this would go on the edit Idea Alpine component. So anywhere up here, I'll put it right after this. So change this to idea was updated. And this should close the modal after we update it. So let's give that another try. Let's go ahead and edit. Let's remove updated, update. And it did close the modal. Oh, yeah. And we also have to listen for that on this component, and then refresh the idea.

Oh, yeah. And we also have to listen for that on this component, and then refresh the Idea. So we can see the changes here in the browser as well. So again, we did that for the setStatus as well on the Idea show. So it's basically the same thing. So we can just add another one here. So we'll just duplicate this, say idea was updated. And then we can make another listener, which does the same thing, but it's just named differently. Idea was updated, okay. So I'm going to refresh.

Idea was updated, okay. So I'm going to refresh. This should remove the updated because I updated it. But now let's go ahead and change it again. Update and let's remove this. Okay, update. And it does update the UI here. So like I said before, we'll focus an entire chapter on having an alert after something happens in our app. So I'll probably do that in the next chapter.

Add Livewire Validation10:13

happens in our app. So I'll probably do that in the next chapter. So maybe some sort of slide out in the top right, or maybe on the bottom right. Okay, now let's work on validation. So the validation will be similar to the create Idea. So let's just grab it from there. So create Idea. These are the rules. So let's grab this. Actually, I'm going to add one more rule here for the category.

So let's grab this. Actually, I'm going to add one more rule here for the category. And this rule, just make sure that the selected category actually exists. So we can do exists on the categories table. And we want to make sure it's the ID. So in our case, we have to make sure that the category is either 1, 2, 3, 4. So that's the corresponding IDs for these. And even if I didn't have that, there would be a database error. But this catches it on the validation layer. So let's grab this.

But this catches it on the validation layer. So let's grab this. Let's put it into our editIdea as rules. So we'll put it up here. And then we can validate it down here. So we just have to do this validate. Okay. And I believe I have the error messages because I copied it already. So if I go editIdea, there should be errors in here. And there are.

So if I go edit Idea, there should be errors in here. And there are. So title, category, and or here's the category and the description right here. Okay. So let's see if that works. So let me just refresh, edit this Idea. And let's go ahead and remove this. Let's remove this as well. And there should be validation errors here. Actually, we have browser validation.

And there should be validation errors here. Actually, we have browser validation. So let me just remove that for a second. So edit Idea. So let's just temporarily remove the one on the title here. Where is it? So it's right here. Let me just remove this for a second to make sure the Livewire validation works. So let's refresh again. Edit remove this.

Enforce Authorization Policies12:22

So let's refresh again. Edit remove this. Update. And it does work. So yeah, let me just put that back. Okay, now let's work on authorization. So right now I'm logged in as my account, and I actually don't own this Idea. I did not create it, but I'm still able to edit. In fact, if I actually log out, since there's no authorization in place, I should be able to edit this Idea.

In fact, if I actually log out, since there's no authorization in place, I should be able to edit this Idea. So let me just update the title here, and it does work. So obviously we want some authorization in place. So for this, we're going to make use of policies in Laravel, which allow you to organize authorization logic around a model. So in our case, we're going to make a policy for an Idea. So let's go ahead and do that. So I'm going to grab this. Let's say IdeaPolicy.

So I'm going to grab this. Let's say IdeaPolicy. And we'll do $model equals Idea. And usually you have to register your policy, but if you name it a certain way, then Laravel will automatically register it for you. And in our case, it's automatic. So let's go ahead and go into that IdeaPolicy, and it's in the app/Policies directory. And we want rules for updating the Idea. So it's update right here. So as you see, it's already accepting a User and an Idea.

So it's update right here. So as you see, it's already accepting a User and an Idea. So what rules do we want for updating? So we should only be able to update the Idea of where the one that created the Idea. So let's do that case first. So simply enough, let's do return $userId is equal to the $idea->user_id. So I'm actually going to cast this second part to an int. When I was testing, this actually returned a string, which caused some issues in my tests. Or if you want, you can just do double equals here instead of triple equals. So now let's go ahead and make use of this policy.

Or if you want, you can just do == here instead of ===. So now let's go ahead and make use of this policy. So let's go back to our EditIdea, Livewire component, and we can do the authorization in here. So to make use of policies, you can use the can and cannot methods on the User model. So there's an example down here. So let's grab this and see what we can do with our app. So let's paste that in. And we are going to grab the User from the logged in user. So let's say auth()->user().

And we are going to grab the User from the logged in user. So let's say auth user. So if the user cannot update the post, very readable. Actually, it's not a post, it's an Idea. And we have that here. So if the user cannot update this idea, then we can abort. And I'll just make use of response()->httpForbidden(), like we've been doing. So let me just import response here. Okay. But we also have to handle the case when the user is not logged in.

Okay. But we also have to handle the case when the user is not logged in. So let's add one more condition here. Let's just say guest. So that means they're not logged in. And we can just do an or here. So if they're not logged in, or if they cannot update the Idea, meaning the Idea does not belong to them, or they did not create the Idea, then go ahead and abort. So let's see if this works. So right now, I'm not logged in.

So let's see if this works. So right now, I'm not logged in. Let's refresh this, not logged in. This will still show up, and we'll remove the editIdea from the menu in a second. But if I try to update, we should get a 403. And we do. So let's try the other case when we're actually logged in, but we did not create this Idea. So let me just log in here. Okay, so I'm logged in. I did not create this Idea.

Okay, so I'm logged in. I did not create this Idea. So we should also get a 403 here when I try to edit. And we do. But for the ideas we did create. So let's go back here. Let's check my ideas. Then we should be able to edit this. Okay. Let me update.

Okay. Let me update. And it does work. Cool. Now, if you remember, I also said I only want this Idea to be editable up to one hour after they created it. So this will prevent a User from creating an Idea. And say, for example, it got a lot of attention and a lot of upvotes, the User can change that Idea entirely, which was not the original Idea. So to prevent that Users can only update up to an hour after creating the Idea.

that idea entirely, which was not the original idea. So to prevent that users can only update up to an hour after creating the Idea. So I believe I have text for that here. Yeah, it says right here. So let's go ahead and add this condition to our policy. So back to our IdeaPolicy. So we can make use of Carbon and I'm just going to add another condition here. So we can use Carbon and there's a now helper, which is Carbon::now(). So the current time of the current time minus an hour, subHour() is less than or equal to the created_at field.

So the current time of the current time minus an hour, sub hour is less than or equal to the created_at field. So idea.created_at then the idea was created less than an hour ago. So we should be able to edit it. So if I save this right now, we should not be able to edit this because I created it two days ago. So if I try doing that, then it should result in a 403 and it does go. So let's make sure we can still update it if it's within the hour. So it's going to do a php artisan migrate:fresh --seed to get new data. And this will make new timestamps for all of our ideas.

So it's going to do a migrate fresh seed to get new data. And this will make new timestamps for all of our Ideas. And I think I have to log in again. Actually, no, I'm still logged in. So let's look for our Ideas. And let's see if we can update this. We should be able to because it was created 19 seconds ago. Okay, so edit, say changed. Let's update and this should work. And it does.

Let's update and this should work. And it does. So just to make sure, let me change the timestamp on that. So that would be in our database to refresh this. Not sure which one it is. So I believe it's this one right here. And let's change the created_at to something in the past. So let me just remove two hours here. And now we should not be able to update this. So two hours ago right here, and we should get a 403.

So let's do that. Actually, it's here in the docs. You can just make use of this can directive, which is just short form notation for this right here. So let's go ahead and do that. So let's say can update Idea, wherever it says edit Idea. So that would be an Idea show, I believe. Edit Idea. So yeah, we can just wrap that directive around this. So can update and there is an Idea being passed here.

So yeah, we can just wrap that directive around this. So can update and there is an Idea being passed here. So we can just do this. And then we can do end can. Okay, so let's see if that works. So I'm going to refresh and this should no longer show edit Idea. So if I were to change the timestamp, so it's within the hour, then the edit Idea should come back. So let's put this back to 2159. Okay.

2359 is what I meant. So it's this one right here. 2359. Okay. And now it's within five minutes and the editIdea should come back and it does. So if you want, you can also wrap this can directive around the HTML that renders the edit form. So that would be in show.blade.php. So right here, we don't need to show this or we don't need to render it if we can't even update it.

So right here, we don't need to show this or we don't need to render it if we can't even update it. So only render it if we can update it. Okay. So that looks good. So one last try. We should be able to edit it shows the menu. So let's change this again. update. It does update for the time-based condition.

Let's go back there. Let me just undo here. Okay. Should not be there anymore. Okay. Go ahead and git add. This is episode 39. git commit episode 39. Edit Idea with policies.

Edit Idea with policies.

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