Hashing Access Methods0:00
In the last episode, I showed you the essentials of Laravel's Contracts component, which is nothing more than a collection of interfaces for all of the various APIs that the Laravel framework exposes. It's really cool. But now, in this episode, we want to figure out how all of this is wired up behind the scenes. For example, let's review Laravel's hashing component. You know that with the facade, we could say Hash::make(password), and that will correctly hash it. So if I were to switch over to Chrome and refresh, that just works straight out of the
hash it. So if I were to switch over to Chrome and refresh, that just works straight out of the box. Very cool. Alternatively, we could just use the helper function. So we could use bcrypt password, and that will achieve the exact same end result like you see there. If we take a look at it, yeah, once again, you can see we are fetching the hash service. We're just passing in the key that we've used. In this case, it's called hash.
We're just passing in the key that we've used. In this case, it's called hash. And then we're calling hash::make directly there. So that means another way we could represent this is by doing app('hash')->make('password'). Let's give that a refresh. That still works. Or, and we reviewed a lot of these basic examples in the last episode, you could get the app object itself and then use array access to track this down. So that would work. And then further, we could reference the class name itself.
So that would work. And then further, we could reference the class name itself. So the actual class that does the work is called bcrypt, Illuminate\Support\Facades\Hash. Let's try that. app, pass that in, and bcrypt hasher. And once again, make the password. I just want to show you all the different ways that you can represent this. So back to Chrome, give that a refresh. It still works. And then finally, our final trick, you could also reference the contract, just like we.
It still works. And then finally, our final trick, you could also reference the contract, just like we reviewed in the last episode. If we take a look at the concrete implementation, you'll see that it implements HasherContract, which is this interface right here. And you can see it's pretty simple. We have make, check, and needsRehash. All right. So if we reference that, like so, we're still going to get the exact same thing. Okay.
Role of Service Providers2:08
So if we reference that, like so, we're still going to get the exact same thing. Okay. So with that recap out of the way, what I really want to talk about in this lesson is, well, how the heck does all of this work? Okay. Well, for any component in Laravel, I always recommend go to the ServiceProvider. That is the class that is responsible for bootstrapping the component into the Laravel framework. And it's not limited to this, but generally that involves registering things into Laravel's IOC container.
And it's not limited to this, but generally that involves registering things into Laravel's IOC container. Or you might see it referred to as the service container. The same thing. So let's take a look. Now, if you ever just want to browse all of the providers, you could do something like this. Do a hunt for service provider, and you can see a bunch of different options here. Or if you're still not overly familiar with the framework source code, you can sometimes guess.
Registering a Singleton2:59
Or if you're still not overly familiar with the framework source code, you can sometimes guess. So if you want to dig into, for example, hashing, as we did here, then maybe you could look for HashServiceProvider, and that might work out for you. Okay. This class bootstraps the hashing service or component into the Laravel framework. And you can see this is all it does. So we reference the application, the container itself, and we register a singleton. Now you might also be familiar with this app bind. It's mostly the same.
Now you might also be familiar with this app bind. It's mostly the same. In fact, behind the scenes, singleton is still going to call bind. But the only difference is, well, we're using a singleton here. We want a shared instance. Or in other words, when we request this service, we don't want a new instance every single time. We don't need it. We just need to new it up one single time, and we can then reuse that single instance throughout our entire application.
We just need to new it up one single time, and we can then reuse that single instance throughout our entire application. Now the thing I want you to pay attention to is right here. This is the key. It can be anything you want. It's just an identifier for whatever this component is. And then notice, when we request it, what we are going to get in return by default, you can always change this, but by default, it's going to return to us an instance of that bcrypt hasher. So now we're starting to figure out, at the very least, how something like this works.
Container Binding Internals4:22
that bcrypt hasher. So now we're starting to figure out, at the very least, how something like this works. When we say app['hash'], we're passing the key that was registered from that very service provider right here. Now why don't we dig into the source and figure out a little more what actually happens when we bind into the container. So I will switch over to Illuminate\Container\Container. This is very much the workhorse of Laravel. And if we take a look at binds, or, well first, let's take a look at singleton, and you'll see that it just defers to the binds method, but it does set this flag right here.
And if we take a look at binds, or, well first, let's take a look at singleton, and you'll see that it just defers to the binds method, but it does set this flag right here. That flag is whether we want a shared binding or not. By default, that will be false, which means for regular things where you need a new instance every time you request it, you can just say app bind. Or once again, if you want the single instance, you could do bind and then set the third argument, but whenever you have those booleans as the third or fourth argument, that gets really confusing, right, especially when you come back six months from now and you can't really remember what false means. So in those situations, always just defer to a different method that has a readable
remember what false means. So in those situations, always just defer to a different method that has a readable name, and that's what has been done here. Okay, so let's see. At this point, when we call it, let's go back to routes.php. Imagine this section right here, app hash. So within our HashServiceProvider, when this gets registered, let's see what happens. Well, abstract is equal to hash. We check to see if it's an array. It's not, so we can skip that.
We check to see if it's an array. It's not, so we can skip that. We then check to see if isNull concrete. Now what is concrete? Well, in this case, concrete will be the Closure that returns the instance to us. So if I show you, this is what that concrete variable would be equal to. So let's see. No, it's not null. Next, we do a check to see if what we have is not an instance of Closure. But it is.
Next, we do a check to see if what we have is not an instance of Closure. But it is. We pass a Closure, so we can skip that. Now we can see we just update a bindings array. So this mostly translates to this, bindings, hash, equals, and then we have concrete will be equal to the callback function or the Closure right here. I'll just say Closure. And then shared will be equal to true in this case. It is a shared instance. So we're simply storing this binding on the object, like you see here.
Resolving Services with make6:54
It is a shared instance. So we're simply storing this binding on the object, like you see here. Okay, so now we figured out the registration process for this. But now what about the other side, where we resolve it out of the container to fetch our object or our service? Okay, well that's where we go back to routes.php, and we have something like this, app 'hash'. Well don't forget, when you call the helper function, it will trigger a make method on your application class. So if we take a look at that, we have a make method right here. And take note that most of the work is actually being done in the parent class, which is the
So if we take a look at that, we have a make method right here. And take note that most of the work is actually being done in the parent class, which is the container. Remember, your Application class extends the Container class. But it does do one important thing. It checks for a deferred surface. We're not going to focus on that. But it does get our alias. And this is sort of how we normalize everything. So for example, if we were to pass hash, well, hash is the alias, so abstract would
And this is sort of how we normalize everything. So for example, if we were to pass hash, well, hash is the alias, so abstract would be equal to the keyword hash. But if we were to pass, let's switch back real quick. If we were to pass a class name or a contract name, well, once we fetch our alias, that's still going to return that same hash key. So now, even if we pass this, abstract would be equal to hash. No matter what we pass here, hash, or the class name, or the contract. And that's where, when I was first learning about all this stuff, I really had to dig in and figure out, well, how does that work?
And that's where, when I was first learning about all this stuff, I really had to dig in and figure out, well, how does that work? Because it can be a little confusing. If we take a look at the getAlias method, and that should be sort on the container actually. Okay, well, we can see that we check to see if we have an alias registered. And if we do, we just return that. Otherwise, we just return whatever the value is itself, which is probably the key. And here we can see, we just take a look at our aliases array on the object. I'm going to show you that in just a minute. And we're just seeing, well, do we have anything registered there?
Aliases and Core Mappings8:56
I'm going to show you that in just a minute. And we're just seeing, well, do we have anything registered there? And if we do, we just want to return what that refers to. So that's how we would translate the contract, or the interface for the hasher, into the key hash. Otherwise, if we don't have anything, we'll just return that itself. Okay, so that's where I want to branch off and figure out, okay, well, where does this get built up? Let me show you. We're going to go back to our application, and we're going to look at a method called
Let me show you. We're going to go back to our application, and we're going to look at a method called registerCoreContainerAliases. This is where all of these are declared here. So let's take a look at hash. Okay. So notice that we could have one or more aliases. For example, like with config in the previous episode, you can see that we have two aliases that basically point to this key. One would be the concrete Repository class, and then the other one would be the Contract.
That is an alias for this keyword hash, and we can see where we assign these at the bottom. For all of the aliases that were defined here as key, which would be this, and then an array of aliases. Then we filter through each of the aliases, and for each one of these, we call the alias method, we pass in the key, and then we give it the alias. So in the context of our hasher right here, we're going to end up doing something like this. We're going to say, set up a new alias called hash, and have that refer to this. Okay, and now if you want to take a look at the alias method, it's just a setter. And just to clarify this, the alias would be hash, and then the abstract once again.
Okay, and now if you want to take a look at the alias method, it's just a setter. And just to clarify this, the alias would be hash, and then the abstract once again would be the contract. So it's just sort of a lookup. For the hash key, the alias is that contract name. So now, if we go back to application, and when we build this up, we get the alias. So remember, if you pass in the contract or the class name, ultimately abstract will be equal to, in our example, hash. So that will get passed to the parent class, which is container. And then for that make method, if we scroll down, we can see what's happening here.
So that will get passed to the parent class, which is Container. And then for that make method, if we scroll down, we can see what's happening here. And first, well, we begin by doing this section right here, where we check to see if an instance is already being managed. And if so, we just return that. You don't have to worry about that right now. But then we get our concrete. So take a look at this. What that's doing is, if I scroll down just a ways, notice that we're just returning this right here.
What that's doing is, if I scroll down just a ways, notice that we're just returning this right here. So this, bindings, hash, concrete, and if you remember earlier, we made that equal to the closure. And by the way, I know this is a lot to take in, and that's why you want to go through this a few times and go through the source code yourself. We're just doing it together. But anyways, this callback or closure is the concrete variable. So we're just returning that. Now if I go back, concrete is the closure.
So we're just returning that. Now if I go back, concrete is the closure. We check to see if it's buildable. In our case, it is. So we defer to the build method. And now take a look. If concrete is an instance of closure, then we call that very function. So this is the code where we trigger or call this closure right here. And there we go. Take a look.
And there we go. Take a look. So this is where, if I switch to the ServiceProvider, this is where we trigger this closure. If it's a closure, it is, then call it, and then pass through the container and any parameters. And that's immediately what we return. So now we're starting to see that when we say app, we figure out what the correct alias name is, whether we pass in the class itself or the interface or the key. Then when we call the make method, we check to see if there have been any bindings. And because we registered a binding within the ServiceProvider, there is. So we just returned this closure right here.
And because we registered a binding within the ServiceProvider, there is. So we just returned this closure right here. And ultimately, within the container, we trigger that closure and we return the result, which in this case is a new bcrypt hasher. All right, so I know that might have been a little overwhelming. There's really no way around it. When you want to learn how the underlying code works, you have no choice but to get your feet wet and just dig in and work your way through the source code to figure out what happens. But trust me, once you get beyond the basics and the fundamentals of Laravel, taking some
