Problem: String Literals0:00
One of the issues with using gates or policies or even the permissions that we have been working with is that we are relying upon string literals. Now, we can't get away from that. There's just no way that we can. But, you know, currently, we have string literals all over the place. Like, for example, you know, our ArticlePolicy, we have several abilities. The easier ones are create, update, and delete. But whenever we need to check if a User can perform one of those abilities, we have to actually type out that string. So there's where we check if the User is authorized to delete. And then inside of the index view for our articles, that's where we check if they can create. Somewhere we check if they can update, right there, and then delete. And those are all strings that, you know, we either have to type or at least copy and paste.
Somewhere we check if they can update, right there, and then delete. And those are all strings that, you know, we either have to type or at least copy and paste. And I want to get away from that because any time that we have to work with a string literal is an opportunity for us to mistype that string literal. And in today's day and age, we have tools available to make this so much easier. And an enum is something that we can use. Because starting with Laravel 11.3, I really mistyped that. But with 11.3, we can use an enum and pass it to the authorized method. So we no longer have to rely upon string literals. We can use an enum, which is a lot safer. So the first thing we need to do is be sure that we have Laravel 11.3 or greater.
Create Abilities Enum1:34
We can use an enum, which is a lot safer. So the first thing we need to do is be sure that we have Laravel 11.3 or greater. And I do. If you don't, then just run composer update and you should be good to go there. So we are going to make a new enum. Let's call this ArticleAbilities. And I'm just gonna let this create it directly inside of the app folder. So now that we have this enum, let's open it up. And we want this to be a string-backed enum. And all we need are just some cases, like create will be simply create.
And we want this to be a string-backed enum. And all we need are just some cases, like create will be simply create. Then the update will simply be update. And of course, the delete will be delete. And there we go. So now we can use this enum inside of our ArticlesController. And I know that we have other abilities, such as viewAny and manage articles. I'm just gonna focus on create, update, and delete because I know where those are used inside of the code. So inside of our controller,
Replace Checks with Enum2:38
delete because I know where those are used inside of the code. So inside of our controller, here is where we check if the user's authorized to create. So instead of using that string, we can use our abilities and we can specify the create value. Then we can do the same thing for whenever we check if the user can update, except that we will use the update value. And then for the destroy method, we will check if the user can delete. And that's it. We are no longer dependent upon the string literals,
And that's it. We are no longer dependent upon the string literals, at least inside of our controller. We do need to go to the index view because, well, we use these here. So we will replace the delete string with the delete enum value. The same thing for update, that will be simply update. And then finally, we will have the create. So let's find that, let's get rid of that, and that's good. Let's also open up the ArticleUpdateRequest and the ArticleCreateRequest. Because here we inspect those abilities, so
Let's also open up the ArticleUpdateRequest and the ArticleCreateRequest. Because here we inspect those abilities, so we just need to change that out with our enum. The same inside of the ArticleUpdateRequest, except that here we check for the update value. But whenever we go to the browser, we can see that articleAbilities is not found, but we can easily fix that. We'll just prefix this with app/. And I know that that's more typing, but that's really not the purpose of using an enum like this.
And I know that that's more typing, but that's really not the purpose of using an enum like this. Using an enum gets us away from having to rely upon string literals. So if I have to type a little more keystrokes to have that safety, I'm all for it. But with that in place, we can see that everything works. We can create, edit, and delete. And of course, if we wanted to test that, all we need to do is just change one of these values. Instead of create, well, let's do this. We can say create article, and let's just make that change for everything else.
Instead of create, well, let's do this. We can say createArticle, and let's just make that change for everything else. Because this is also one of the beautiful things about using an enum, is that if we ever decide to change the ability names, now that we did, we are not authorized to do anything. However, we can go back to our ArticlePolicy, and we can make those changes so that we now have createArticle, updateArticle, and deleteArticle. And since we are now dependent upon our enums, I only had to make those changes in two different places, inside of the policy and inside of the enum.
I only had to make those changes in two different places, inside of the policy and inside of the enum. Everything else just worked like it should. So now back inside of the browser, we can refresh, and voila. We can see that we can create, edit, and delete. So not only will using enums give us the ability to get away from using string literals everywhere, it also makes our code much more maintainable. And I am all for that. So we can use these enums now whenever we check if a User is authorized or
Enum for Permissions Too5:34
And I am all for that. So we can use these enums now whenever we check if a User is authorized or if we need to inspect if they can perform a particular ability. But I want to take this a step further, because as we look inside of our ArticlePolicy, once again, we are relying upon a bunch of string literals whenever we check if a User has a given permission. Like viewAny, we have to pass all of these string literals. And I know that these literals match values that are in the database. So it's not like we are going to make anything easier.
And I know that these literals match values that are in the database. So it's not like we are going to make anything easier as far as keeping things in sync between our code and the database. But we will definitely make things easier by getting away from string literals. So instead of, well, this right here, for createArticle, if we check if the User has the permission to create an article, I want to do something like this, to where we would have an ArticlePermissions, and it would have a create value. That way, we don't have to rely upon the string literal value. So we need to make another enum called ArticlePermissions.
That way, we don't have to rely upon the string literal value. So we need to make another enum called ArticlePermissions. Let's go ahead and let's open that up, so that we can first of all make this a string backed enum. And then we have the create case, which will have a value of, well, whatever that was, it was articleCreate. But of course, this isn't going to actually work for us, at least right now, because the hasPermission method expects a string. So let's open up the User model, and here's hasPermission. So we can make this work with strings and enums with just really a few lines of code.
Update User Permission Methods7:17
So let's open up the User model, and here's hasPermission. So we can make this work with strings and enums with just really a few lines of code. We will first of all check if the provided permission is an instance of a backed enum. And if it is, then we are just going to set permission equal to the value of that enum. That's going to give us the string value that we can then use to see if we have a permission for, and everything is going to work exactly like it did before. hasAnyPermission is going to be a little bit different, because we are working with an array of permissions. But this should be relatively simple as well,
because we are working with an array of permissions. But this should be relatively simple as well, because we can provide our own function so that we will first of all basically do the same thing. If the value is an instance of a backed enum, we will get the value of that case. And of course, if it's just a regular string, then we don't really do anything except call strtolower, passing in the value. And yeah, everything should work like it did before. So let's go back to our ArticlePolicy, let's import that class. And inside of the browser, we see the Create button is still there.
Validate Policy with Enum8:24
So let's go back to our ArticlePolicy, let's import that class. And inside of the browser, we see the Create button is still there. And if we change the value of our enum to articleCreate1, then that of course is not the correct permission. And so the Create button is now missing. So now it's just a matter of taking all of the permission values that we have and defining a case inside of the ArticlePermissions enum. I'll do that off screen because, well, that's a lot to do. But you get the idea. By using an enum, we get away from using string literals,
But you get the idea. By using an enum, we get away from using string literals, which takes away a lot of the, well, the error-prone-ness, if that's a word, of us humans typing things out. And of course, it makes our code much more maintainable. And as our application grows, and especially if we start working with other people, that's definitely going to be very important.
