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

Review: Using Payment Class0:00

Real-time facades in Laravel are a little like magic, in the best possible way. You try it out, it works, and all you can think to yourself is, huh, how did they do that? Well, I'll show you how. It's not so hard. But first, a little review. Here I've set up a Payment class with a method called process. So yes, of course, I could instantiate that, and then call the method process, and then let's return that directly from the route. And sure enough, if I switch to the browser, it works.

Building a Traditional Facade0:28

let's return that directly from the route. And sure enough, if I switch to the browser, it works. Alright, let's switch back. First, let's go ahead and simplify this, and import it at the top. Next, what if I wanted to use this as a facade? Well, traditionally, you gotta create the file. So let's do that now. I'll set up a class called PaymentFacade. There we go. We will need to extend the Facade parent class there.

There we go. We will need to extend the Facade parent class there. And then if you watched the previous episode, you know that you need to add a getFacadeAccessor accessor as a static method. This should return a key that will be referenced when we're resolving the underlying class out of the service container. So in our case, we're going to return a path to the Payment. This is our underlying class. Now a quick note on this. Even though I haven't bound this key into the container, that's okay.

Now a quick note on this. Even though I haven't bound this key into the container, that's okay. As a second step, Laravel will check, well, is this a real class that exists? If so, that's probably what you want, so I will resolve that out of the container. Okay, so great. If I switch back now, I want to get to this point, PaymentProcess. So if I switch back, refresh, of course it's not working because it's not yet referencing the facade. Let's change it, though. Use PaymentFacade, and then we'll give it an alias, back to payment.

Let's change it, though. Use PaymentFacade, and then we'll give it an alias, back to payment. Now if I run it, it works. So here we have a basic illustration of a facade in Laravel. It's sort of like a proxy. But here's where it gets fun. What if I brought this back to what we had before? I then deleted the facade entirely, and in fact, I'll copy that because we'll reference it later. Now, if I switch back, it's going to fail again, of course.

Introducing Real-Time Facades2:06

it later. Now, if I switch back, it's going to fail again, of course. However, check this out. If I prepend facades to the namespace here, and I come back, run it again, it works again. This is a real-time facade. And again, notice how it makes you sit there for a second, and you think, what on earth? How did they do this? It's not so hard. Now, before I lift the hood, you first need to understand the SPL autoload register function. It sounds a little confusing, but at its core, it allows you to register a function that

Understanding SPL Autoloading2:29

Now, before I lift the hood, you first need to understand the SPL autoload register function. It sounds a little confusing, but at its core, it allows you to register a function that will be triggered any time a new class is referenced or instantiated. And in fact, you can have many of these. So typically, you don't have to worry about this because we leverage PSR-4 autoloading. But what about in situations where maybe you are dynamically generating some of these classes? Well, hint hint, this would be a good location to set that up. So first, the name, that's going to be the name of the class that you are instantiating. So if I were to die to show you the name real quick, and then let's get rid of this.

So first, the name, that's going to be the name of the class that you are instantiating. So if I were to die to show you the name real quick, and then let's get rid of this. So now I'm just referencing a Payment class, and php has no idea where that is or what it is. So if I come back and reload the page, sure enough, we have triggered our function payment. So yeah, you know, you could, you'd never do this, but just to show you real quick, you could say, all right, if you're trying to load Payment, then let's whip one up on the fly, like we're making burgers, and if I come back and reload the page, it did find the Payment class, but now it's failing for a different reason. There's no process method.

the Payment class, but now it's failing for a different reason. There's no process method. But the key thing here, of course, is we have now hooked in and determined what to do when you instantiate this class. All right, let's make it a little more fun, though. Now what I'll do here is we're going to try out the same approach where we prefix a key. But Laravel is already looking for that key facades, so we'll call it LaracastFacadesAppPayment. All right, so now, once again, the browser doesn't know how to find this. Let's inspect it. Let's say, let's pull in the String class, and we'll say, well, if what you're importing

Generating Facades from a Stub4:04

Let's inspect it. Let's say, let's pull in the string class, and we'll say, well, if what you're importing starts with LaracastFacades, then we know we need to set up one of our own custom real-time LaracastFacades. And let's clean that up, and then pull these to the top. So if this turns out to be true, it's almost like a signal that we need to generate our own facade and then require that file. Let's set up a little stub here, and I'll put it in my app directory. We'll call it facade.stub, and then I'm going to paste in the facade that we created earlier for a payment.

We'll call it facade.stub, and then I'm going to paste in the facade that we created earlier for a payment. However, this is a stub, so I don't want to hard code anything. I'll use a little template syntax here. Namespace will be added here. The class name will be added here, and then this will maybe be the accessor. There we go. All right, I'm going to switch back to my routes file now. I'm going to pull in our stub using a simple file_get_contents. It's in the app directory, and we called it facade.stub.

I'm going to pull in our stub using a simple file_get_contents. It's in the app directory, and we called it facade.stub. So now this $variable contains this. The next step is to perform a few string replacements. Let's say we're going to do a str_replace, and I need to replace three things. Let's see what we have. namespace, className, and accessor. className, and the third one was accessor. All right, what will those be replaced with? And then finally, what are we looking in?

All right, what will those be replaced with? And then finally, what are we looking in? We're looking in the stub, and then I will overwrite that. Okay, how do we determine what the namespace is? Oh, that's a little bit harder, actually. Let's start with className. So if right now this variable is equal to that, then the class name itself would be the base name here, and Laravel offers a helpful little function called class_basename. So we'll pass that in, and this will now return to us a payment, which is what we want. But next, how do we determine what the namespace is?

So we'll pass that in, and this will now return to us a payment, which is what we want. But next, how do we determine what the namespace is? Okay, let's see. Right now, once again, we know the name variable is equal to this. So why don't we reverse these backslashes to turn it into a directory, like this. We're going to look for any backslash. We're going to replace it with a forward slash using the full class. So that will now give us, in this case, Laracasts Facades, app, payment. Next I'm going to get the directory name there. So that will now turn it into this, and that should be correct.

Next I'm going to get the directory name there. So that will now turn it into this, and that should be correct. So the only remaining step is to turn it back into a backslash. Look for any forward slash, turn it back to a backslash using this, and that will give us this for our namespace. All right, so we have that. We have our class name, the accessor. So remember, that's going to be the key that's returned. Well, think about it. The accessor should be the underlying class.

Well, think about it. The accessor should be the underlying class. So in our case, it should be this Payment class here. All right, so how can we determine that? Well, we could do class_basename again, but think about it. That's going to give us payment, and that's not what we want. We want the full path. So we actually want, instead of payment, we want app\Payment, right? So why don't we do this instead? We'll extract some of these, and we'll say our namespace is this.

So why don't we do this instead? We'll extract some of these, and we'll say our namespace is this. Our class name is this. And then finally, our accessor name, or our accessor, excuse me, will be, well, we're going to start with the namespace. So at this point, that would be layer-cast-facades\app. Why don't we do a str_replace? It's kind of quick and dirty, but this should be fine. And we're going to strip off layer-cast-facades because we know that won't be it. That should now give us the correct namespace.

And we're going to strip off layer-cast-facades because we know that won't be it. That should now give us the correct namespace. So it would be something like that. So the only remaining step would be to tack on the class name itself, right? So I think that will give us, we'll have to check, but I think that should give us something like App\Payment. Yeah. All right, well, if we made a mistake, we will catch it pretty quick, but here we go. So what I'll do here is die and dump the stub and take a look at our template. Come back to Chrome, refresh, and let's see.

So what I'll do here is dump the stub and take a look at our template. Come back to Chrome, refresh, and let's see. That all looks correct. The class is Payment. It extends the Facade, the Accessor. All of this looks correct to me. So we generated our Facade. The next step is to create it. File, putContents, and you can put this anywhere you want. I'm just going to throw it right back into the app directory.

File, put contents, and you can put this anywhere you want. I'm just going to throw it right back into the app directory. So let's see. We want the name of the class, Payment in this example, and then maybe we will add the facade suffix there, .php, and we will put the stub there. So if I left it like this and refreshed, it's still going to fail. However, if I come back, you'll see it did create a new PaymentFacade class, and all of this again looks correct to me. So there's only one remaining step. We've created the file, but we haven't yet required it.

So there's only one remaining step. We've created the file, but we haven't yet required it. Let's save it like that and then require the path to this new file we created. And yeah, this, a little clunky, but this is what we end up with. And reformat. So if I now come back, refresh, it works. So we just created our own custom real-time facade on the fly. Now, of course, in real life, Laravel is going to do a little bit more. It's going to cache this because at the moment, no matter what, every time the page loads, we are generating this file.

It's going to cache this because at the moment, no matter what, every time the page loads, we are generating this file. But at the very least, this gives you a very rough idea as to what's happening. It's the same basic path where we added a special prefix to the namespace, and then we check, all right, is that what we're working with? If so, you're using a real-time facade. So let's go ahead and build the template, what the facade should look like. We will then write that file to your system, and then we will require it. And once you do, well now, a Payment class exists, and we can call it. So let's try one other example.

And once you do, well now, a Payment class exists, and we can call it. So let's try one other example. Let's say you have a class called Pizza, and maybe a method on there called deliver. And let's try to use that as a real-time facade. So we'll change this to Pizza::deliver, and we'll import that. Now it's not going to work, right, because we're not referencing a facade. Let's use a real-time facade now. Come back, refresh, and now that works. So now that you have a basic understanding of what's happening, let's actually look at the Laravel source code.

Tracing Laravel Source Implementation10:54

So now that you have a basic understanding of what's happening, let's actually look at the Laravel source code. Now if you watched the last episode, we learned that as part of the kernel, and actually let's go to the parent here, one of the things it does is it registers the facades. So if we take a look at that class, here you can see the alias load and then a method called register. All right, let's go to that method. prependLoaderStack. And if we take a look at this, what do you see? SPL autoload register.

And if we take a look at this, what do you see? SPL autoload register. It's the same thing. So here Laravel is saying, all right, I have this load method on the class, and I want that to also be responsible for catching and handling when these classes are instantiated. Because remember, you can have a stack of these functions, almost like a queue, to handle it. So let's look for a load method. All right, here's what we want. So notice, if static facades namespace.

All right, here's what we want. So notice, if static facades namespace. What's that? Well, it's checking. Does the namespace begin with facades? Let's go back. Yes, that exists. Next we're checking. All right, well, the class, the alias you're trying to load, does it begin with facades? Yes, it does.

All right, well, the class, the alias you're trying to load, does it begin with facades? Yes, it does. So we will load the real-time facade. Let's take a look at that method, ensureFacadeExists. Scroll down, and you're starting to see kind of what we did earlier. So it's checking. Have we already created this file in the patch? So remember when I talked about caching? That's what it's doing here.

So remember when I talked about caching? That's what it's doing here. It's checking. Well, does this file already exist? Have I created the Facade in the past? If so, I'm just going to return that. Otherwise, I'm going to fetch a facade stub. Take a look at it. Basically, what we did together a few minutes ago. We will format the facade stub.

Basically, what we did together a few minutes ago. We will format the facade stub. This is where it does a simple string replace, again, very similar to what we were doing earlier. Let's go back again. And Laravel's then writing that newly generated facade to this path. We return the path, and then you can see we require that file path. It's the same thing, isn't it? Build up the template, write the file, return the path, then require the path. It's the exact same thing.

Build up the template, write the file, return the path, then require the path. It's the exact same thing. And that's it, believe it or not. That's everything that takes care of real-time facades. Let's go over it one more time, 30 seconds, really quick. We know that when Laravel registers the facades, it calls this register method. And it hasn't yet been registered, so it calls a method here, prepend to loader stack. We next learned about SPL autoload register. Laravel says, I have this load method that I want to be included as a autoload implementation. Laravel's checking, all right, does it begin with the facade's namespace?

Laravel says, I have this load method that I want to be included as an autoloader implementation. Laravel's checking, all right, does it begin with the facade's namespace? If so, you're probably trying to load a real-time facade. So we load that by ensuring it exists. Now if it does exist, great, just return and require it. But if it doesn't, then we need to dynamically create the facade. So we'll build up a template, we'll format it, and then we'll write that template to the framework cache directory, and then we will require that. Once again, right up here, we'll require that new file we wrote. So that means if I look in the storage/framework/cache directory, sure enough, there's your

Once again, right up here, we'll require that new file we wrote. So that means if I look in the storage/framework/cache directory, sure enough, there's your real-time facade. How cool is that?

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