From View to Response0:00
In the previous episode, you learned how a route returns a response, but now let's kick it up a notch. Let's figure out how a Vue that includes Blade directives is compiled to vanilla PHP that is then served to the browser. Now to begin, let's toy around. You know that any controller or route can return a call to the Vue helper function, right? So you might say, return Vue, and then you provide the name of your Vue. Alright. However, if you return this from a route closure or a controller action, you get an instance.
Alright. However, if you return this from a route closure or a controller action, you get an instance of Vue. Now if we take a look at that though, let's find it. There is a toString applied here, and that we'll call render. Now render, as you can imagine, will compile and render the contents. Okay, so that means if I run this again, we get a Vue instance, but if we echo it or convert it to a string, sure enough, we get the compiled PHP. And if that's the case, and if you watched the previous episode, you'll remember that in your router, when it prepares a response, as you see here, well, it's going to go through
Tracing the View Helper1:34
see here, it's just echoing out the rendered contents of that Vue. So this specifically is echoed along with the headers. All right, but still, let's back up a little bit because maybe at this point, we don't even really understand what happens when we call Vue. All right, let's get started. First up, Laravel includes two different sets of helper functions. So you have the support helpers and then the framework foundation helpers. In our case, this will be for foundation, and we should see a Vue function here. All right, so that means when I call Vue, we are executing this function. And immediately we can see, all right, we're setting up a Vue factory, and then we're calling
All right, so that means when I call Vue, we are executing this function. And immediately we can see, all right, we're setting up a Vue factory, and then we're calling a make method on that Vue factory. All right, let's take a look at that Vue factory. There it is. And then we called a make method on it. Okay, so now we know when I call this Vue helper function, we're ultimately calling a make method here. We're trying to get the evaluated contents for a given Vue. And remember, at this point, the Vue it's receiving is called welcome.
Finding View File Paths2:59
there's a lot to cover here. Okay, so next we're trying to find the given Vue. So we're tracking down the path to the welcome.vue. Let's figure out how it's doing it. So we have a find method, and it looks like it wants a VueFinderInterface. Here's the interface, and in phpStorm, I can hit Command + Option + V to find any implementations of it. So we come to this file VueFinder.php. This is what Laravel is using to track down the Vue you're looking for. Okay, so we're going to find the welcome.vue at this point.
This is what Laravel is using to track down the Vue you're looking for. Okay, so we're going to find the welcome Vue at this point. And immediately it says, all right, do I have something cached? So I have this Vue's property. Is there anything in there? Well, at this point, no, it hasn't been cached yet. Next it's checking, do we have any hint information? And once again, it's checking to see if you have, for example, a package directory. Like that. In our case, no.
Like that. In our case, no. So we'll skip over it. So we can see, all right, we're going to cache it. So we're going to store the name of the Vue, welcome, in this Vue's array, and we're going to find in path. So we're still trying to track down where this welcome Vue is. Okay, find in paths. Let's take a look at that. For each array.
Let's take a look at that. For each array. So we're looking through this paths array. But how did we find it? Let's scroll back up one more time to that find method. We're giving it an array of paths, but let's keep going up the chain. How exactly do we know what those paths are? All right, well here, once again, it's being accepted through the constructor, but I still want to figure out how we get those paths. So in these situations, often they will be defined within the associated service provider.
want to figure out how we get those paths. So in these situations, often they will be defined within the associated ServiceProvider. So let's see if we can find it. Now you may not know what the name of the ServiceProvider is, but you will often know the component name. We know we're working with Vue here, so maybe we're going to guess VueServiceProvider. Yeah, there it is. Otherwise, you can just hunt through it manually. So if we scroll up, for any ServiceProvider, you'll often want to look for this register method.
So if we scroll up, for any ServiceProvider, you'll often want to look for this register method. This is where you register the component with the framework. So you'll see it registers the VueFactory, it registers the EngineResolver, and it registers the VueFinder. It looks like that's the one we want. So let's see what that looks like. Register VueFinder. Okay, so it binds something into the service container. And here's where we instantiate it.
Okay, so it binds something into the service container. And here's where we instantiate it. So we're giving it out files, that's just the FileSystem class. And then here are the paths. So it looks like the paths are defined within your config/vues directory. And if we take a look at that config, vue directory, sure enough, there it is. So by default, Laravel will look in your resources/vues directory, right? But you can change that or extend it or add multiple locations if you wish. So now we're making a little progress. We now know where this paths directory is coming from.
So now we're making a little progress. We now know where this paths directory is coming from. And if you want to take a look at it in the terminal, sure enough, you can see right there, we only have a single one. Let's get back to work. So we're still trying to hunt down that welcome view. So we find within this path at the moment. And we first say, all right, get possible Vue file names. All right, what's going on here? Take a look.
All right, what's going on here? Take a look. So remember, at the moment, this name variable is welcome. We're still trying to track that down. So we're going to map over all of the various extensions that we can handle. For example, php or .blade.php or .html. And all we're doing is returning an array where we update the path. So now you can see it's saying, all right, look for a period and replace it with a slash. So again, if you had a view called about.company, it's saying, all right, well, let's make this into a file path.
So again, if you had a view called about.company, it's saying, all right, well, let's make this into a file path. So look for about slash company and then a dot and then the given extension. So it's going to set up an array where one item is this, one item is that, one item is this. I think that might be, there might be one other, but that's basically what it's doing. So now you have an array of potential file paths that you're trying to load. All right, let's get back to work. We'll go back to the find method. We find in paths.
We'll go back to the find method. We find in paths. And there you go. So let's do this together. Let's dd this just to get a little bit of a visual. Run it again. We load our view. And there you go. We have an array of potential file names, including CSS. I'll be honest with you, I'm not exactly sure how that works.
We have an array of potential file names, including CSS. I'll be honest with you, I'm not exactly sure how that works. I'll have to look into that. But either way, we have paths that might be what you're trying to load. Okay. Next, we iterate over these. And it's fairly basic. For each one, is this a file? And if it is, that's probably the one you mean to load. So if that file exists, return the path to the view file.
And if it is, that's probably the one you mean to load. So if that file exists, return the path to the view file. So here at this point, this is what we would return. Let's run it again. And now we have the path to the file you're actually trying. All of that work was to track down the correct view you mean to load. Okay. Great. So let's see. We go back to that find method.
So let's see. We go back to that find method. And at this point, we have found the path to the view and we're going to cache it so we don't have to do it in the future. So let's now jump back up to our view factory. And at this point, path is now what you see right here. It's the path to the view. Okay. What's the next step? We set up the data.
Creating the View Instance8:25
What's the next step? We set up the data. So don't forget, when you have a view, you can set up whatever data you need as part of that. All right. Next, we create a new view. So if you're not familiar with tap, I find this often scares people who haven't learned it. tap is very simple. All you're doing, it's basically the equivalent of saying something like this.
Tap is very simple. All you're doing, it's basically the equivalent of saying something like this. view equals view instance. And then this call createView. That's it. That's just a coding preference thing. So anyways, if I bring this back to what we had before, we build up a view instance and all that does is instantiate a View class. And we'll come back to that in a minute. We give it the engine that you want.
And we'll come back to that in a minute. We give it the engine that you want. So it's figuring out, are you loading a basic php? So if, for example, if you're loading welcome.php, well, you don't need to first send that through the Blade compiler. It can go straight to the php engine. So that's what it's doing there. Anyways, we'll go back. And ultimately, that view instance is what we are returning from the make method. Okay.
And ultimately, that view instance is what we are returning from the make method. Okay. So now we know, let's recap. Now we know when I say view('welcome'), what's being returned is a view instance. And we can see that right here. That view instance will look like this. And if you take a look at the methods, this is the class that has that toString that we'll call render. So now we know if we echo it or convert it to a string, we get the rendered contents. Okay.
So now we know if we echo it or convert it to a string, we get the rendered contents. Okay. So when it's converted to a string, it calls this render method. And right here, this is where it gets converted to what we want. So let's take a look. render contents. Okay. Once again, we're dispatching an event. And I'm sorry, here's where we would actually get the contents. All right.
And I'm sorry, here's where we would actually get the contents. All right. So let's take a look. And if I scroll down. So we're now deferring to the appropriate engine. And don't forget, there's a php engine, there's a compiler engine. And we're basically saying, give me the contents associated with that file path. Now, real quick, if you're curious, how do we know which engine we're using? Don't forget, that was all in the view factory. Let's find it.
Don't forget, that was all in the view factory. Let's find it. view factory. So if we go to the constructor here, okay. So we're accepting the engine resolver there. And in the ViewServiceProvider, let's see where we build up the factory. Okay. So here, we figure out what the engine resolver is. If we scroll down, we can find that. There we go.
Resolving the Render Engine10:57
If we scroll down, we can find that. There we go. We build up an engine resolver. Here's all the different file types we can handle, basic files, or PHP, or Blade. And for each one, we register that engine. So we register a standard file engine. We register a PHP engine. And notice each of them basically has its own handler for how it goes about things. So for this one, for Blade files, we'll have a compiler engine that uses a Blade compiler. But still, how do we know which one we're using?
So for this one, for Blade files, we'll have a compiler engine that uses a Blade compiler. But still, how do we know which one we're using? Well, don't forget, if we go back to our view factory, let's see if we can find it. Here we go. So here's that make method. And when we call the view instance, this is the important thing. This is where it figures out, okay, well, what engine would be appropriate given the current file path? And if you take a look at that, we figure out what the extension is, php, something else, .blade.php.
And if you take a look at that, we figure out what the extension is, php, something else, .blade.php. And then we get the corresponding engine. We looked at that earlier. And we call resolve. So if we now take a look at resolve, this is where it gives you the appropriate one. So if we've cached it, then just return that. Otherwise, call the user function that corresponds to the current engine. So again, I know this is getting a little complicated. Try to go along for the ride.
So again, I know this is getting a little complicated. Try to go along for the ride. These are the sorts of things. You don't really need to spend a lot of time learning. But anyways, if we scroll down, for each one of these, we're calling the function that corresponds to the file type. So in our case, take a look. If we are loading a view called welcome.blade.php, that means if we scroll down, we're using this compiler engine. All right, we're getting close, I promise.
this compiler engine. All right, we're getting close, I promise. So now, using the compiler engine, get the contents for that path. Let's go to the compiler engine. Go to the get method. We collect all the view data. So this would be the data you pass to the view, any shared data that should be available to all views. And then we defer to a parent's get method. And if we scroll down, here we go.
Compiling Blade to Cached PHP12:54
And then we defer to a parent's get method. And if we scroll down, here we go. All right, so this section checks. Have you changed the file? If so, we have to recompile it, of course. However, this is also going to handle the case where you haven't cached at all. So if you're loading it for the very first time, we need to compile it down. Okay. So once again, path is a path to that welcome.blade.php file, and we're going to compile it down using that Blade compiler we talked about.
So once again, path is a path to that welcome.blade.php file, and we're going to compile it down using that Blade compiler we talked about. So let's go to compile. Here we go. We're setting the path. We're looking if there's anything in the cache path. And if there's not, then we compile the string that we fetched when we load that welcome view. So what this is saying is, file, load this file for me. Load all of that, and we're going to compile it with Blade.
So what this is saying is, file, load this file for me. Load all of that, and we're going to compile it with Blade. Now we'll talk about that compile string method in a minute. But over here, we take care of any of PHP's tokens. We figure out, do we need to close out PHP? We add a quick lookup to the original file. This is especially useful for an IDE like phpStorm. It allows you to associate the cached view with the original Blade view. Anyhow, once we've compiled it down, so we've converted all the Blade directives, we've compiled all of that down, then we write those contents, basically file, put these contents.
Anyhow, once we've compiled it down, so we've converted all the Blade directives, we've compiled all of that down, then we write those contents, basically file, put these contents to the appropriate cached path. And if you take a look at that, it's going to look in your cache path. It'll send the current path through shout1, and that will ultimately give you something like a storage/framework/views directory, and you'll end up with something like this. All right, I promise we're super close here. One last step. What is compile string? So this is where we load the Blade file, we pass that Blade file as a string to compile
What is compileString? So this is where we load the Blade file, we pass that Blade file as a string to compileString, and here's where, and there's a lot going on here, but this is where it'll look for any of your directives. So do you have any PHP directives in your Blade file? If so, we need to store all of them so we can later swap them out with the correct versions, the versions that PHP itself will understand and be able to execute. And again, a lot going on here, we're going to skip over some of this, but ultimately we return that resulting string. And that is what happens when you call this render method.
we return that resulting string. And that is what happens when you call this render method. We render the contents, and then the rest of this is handling when to flush, catching any exceptions as quickly as possible, but we ultimately return the response or the contents from this method. So now, if you switch back to the previous episode where we learned about the router, and we learned how it converts to the proper response type, now we've learned that view, that view object is being passed to a new response instance, and we learned that ultimately when that response is sent, it will send the content, which literally echoes it out. So this is sort of like saying echo that view instance.
when that response is sent, it will send the content, which literally echoes it out. So this is sort of like saying echo that view instance. And lastly, we learned for the third time on your view object, if it's echoed, if it's treated as a string, then it will call render, and render will render those contents down, and it will the first time write to this cached file. And if you ever change it, it will delete that and then rewrite it for future runs. So I get it. Lots and lots going here. I certainly don't expect you to have followed every piece of that. That's OK.
I certainly don't expect you to have followed every piece of that. That's OK. You don't need to. The main goal is to have a basic understanding of what's going on here. So when you call that view function, what essentially is going on in order to convert that view file you're referencing into the proper response?
