Routing, Controllers, Views - Part 1 | PHP MVC Framework from Scratch

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] what's up guys the code hulk is here welcome to the first part of building an mvc framework using php in this part we're going to implement custom routing we're gonna implement controllers views layouts and come up to the project structure so let's get crazy and start building our own mvc framework in php i want to highlight that this video the only purpose of this video is pure educational okay so we're gonna learn something but it's not it's not recommended to take this and use it on production websites all right let's start and i'm going to create index.php which will be the main file entry script of our mvc framework and for now i'm just going to write echo hello world okay i'm going to open the terminal i'm going to use phpstorms integrated terminal which i said to use the git push so you can use any terminal basically just make sure that you have php command globally available okay we type php minus s localhost port 8080 which will start php's built-in server and when we open localhost port 8080 in the browser it should give us hello world no matter what path we provide right here whether it will be users for example it's gonna show hello world it's it's not gonna show not found this happens because always this index.php is served and this index.php in general will be our entry script all the requests will be handled handled by this and then we're gonna set up some routing okay so let's have a look in the index.php and let me show you how i imagine this how it should be so i want to create a variable of application new application i want to create a variable for example for rotor okay is new rotor i want to tell the application to use the rotor and pass the rotor right there and i want on the application to call run method which will simply handle everything but on the rotor i need to be able to configure some roads for example when get request is made on slash it should execute the following function function this which will return simply hello world okay we can do even better and avoid this rotor completely so make sure that the application will create rotor in its constructor and we can use we can configure the roads in the following way so we will remove this creating new rotor just like this we will remove this use rotor it is user rotor but we are going to still remove this and on the application i'm going to call on up rotor let's configure git url so for this we have to create at least two classes application and rotor so let's do this i'm going to create folder core which will be the core basically core folder which will contain all the classes of the core cms later we're going to make this core installable using composer so we're going to try to make our mvc framework as close as one of these out there popular frameworks symphony lre2 and we want to make this core installable because if we just manage this core and release some updates and people have installed that core they can update their core on their websites right so i'm going to create now application class and the application needs obviously some kind of constructor and in the constructor it must create the instance of the router okay so i'm going to create another class which will be rotor and the router needs get method but let's do the application class first so i'm going to create right here public i'm going to use php 7 point force features which is typed properties okay so i'm going to specify that the rotor variable basically will have type of rotor and right now phpstorm puts the red underline on this typed properties are available to php 7.4 only i can click this link switch to php 7.4 language 11 in phpstorm and the error disappears and basically we can write the php 7.4 or i can open the settings and configure their p that the php storm to use php 7.4 so if we just don't do this it doesn't mean that it's not going to work it will work because i have installed php 7.4 on my machine make sure you also have a php 7.4 install on your machine if you don't simply go to the xampp installation download the latest from apachefriends.org download the latest version which includes includes php 7.4 and install it okay if you are on a different operating system you can still find a suitable version for you for linux or for for mac os okay so i have php 7.4 i can hit this link or i'm going to open the settings file settings and right here i can say search for php so we need to find the language section where it is language and frameworks php and right here the php language language level is set to 5.6 which is very old and i'm going to set it to 7.4 hit the ok and the error basically disappears or i could do it easier just i wanted to show to you how you can do this from the settings okay now i'm going to create this router equals to new router okay just like this now if we just open index.php right here and if we just include this application class we should have access on the rotor property okay so how should we do this we need to write require once right here to include the application require ones or require include ones whatever you like and in the application class we need to also require rotor because the application class basically creates an instance of the rotor so and imagine that our framework will get larger and larger and we have to create more and more classes and we have to always require them it's not actually very good practice and not acceptable in 2020 so we have a better tool for this which is called composer probably you are already familiar with it so we need to create our project as a composer project so if you don't have composer get on the following website getcomposer.org or just type composer in the google the very first the very first website will be what you want just download for your operating system install it and in the terminal in the command line you will have composer command globally available so let's do this i'm gonna open second terminal and just type there composer init so i have composer command globally available so i can run this right here it asks me what's the package name and vendor name so this is the vendor name basically and this is the package name i'm going to leave it as it is hit the enter i'm going to leave the description i'm going to leave the author it automatically takes picks up my my information okay minimum stability package type i'm going to leave basically everything empty okay so i'm going to hit just enter multiple times and finally the composer json file was generated so let's have a look right here in the project we have composer json if we open here we have all the information what we provided name authors and requires empty object this is on which packages our mvc framework should be dependent and right now it's not dependent on anything okay so the only thing i want to configure right here right here is the autoload property okay so i'm going to type auto load and php store autocompletes it for me then i'm going to choose the psr for standard for autoloading and i'm going to specify that the app namespace corresponds to the current folder and what does this mean this means that any class which is created right here in the in the project folder we should be under app namespace if we want autoloading to work and if we want to avoid writing require or includes on the classes we need to configure autoloading okay so now what we need to do is that we need to change our application and rotor namespaces okay i'm going to specify that the rotor namespace is up backslash core okay so because every class in this in this folder in the main folder phpm is a framework folder should be under up namespace so we have nested folder right here core and namespace name must match to the folder name okay so that's that should already already uh be autoloaded if we try to include the rotor the next thing is to go to the application and have the same namespace right here basically i'm going to copy this from the rotor put it right here and i'm going to also specify right here in the doc block what is the uh what's the namespace without the namespace and the semicolon in the rotor as well so i just type up backslash core okay now we need to open the terminal once again and because we configured the autoload right here we need to run composer update which will read this auto load do some things for us and it will also create vendor folder right here with couple of uh files inside with the composer folder and this will help us for autoloading so it should need couple of seconds so let's wait until this is done meanwhile i'm going to go to the index.php it is actually already done and vendor folder appears right here and right here we have composer and autoload so what i need to do is only require the auto load so i'm going to use the d magic constant from the current directory i want to go to the to the inside the vendor folder and import uh include this auto load php so now every class if we use it with the correct namespace can be autoloaded for example this application so this application is under namespace up core if i use it with the following namespace backslash up backslash core so i can actually create an instance of this and in the same way if i go inside the application and i use the rotor i need to specify the namespace name but right now application and router are in the same namespace both are in the upcore namespace so i don't have to specify namespace name right here in this case because they are in the same namespace okay right here we can do it even in a different way and remove this up right from here and just write use up backslash core right here okay excuse me up backslash core application so basically i'm telling that hey i'm going to use upcore application right here in this file which will be the application class and now i can create an instance of the application all right so good so far so far so good and we need to create now two methods get method on the rotor and run method on the application so let's do the easy one first and i'm gonna create a run method on the application and we're gonna do a couple of things right here so i'm going to type to do right there let's go to the rotor and i'm going to create right here a public method get which will accept the path and it will accept the uh callback function okay so whenever the path is this this callback must be executed and we need to save this so this is basically an associative map so if i just copy and paste this and call this contact for example and right there contact this is a map i'm configuring that the on this url this function needs to be executed and i want to save this somewhere and then whenever run is called i want to decide what what function to execute okay so let's go to the rotor and right here i'm going to create a private or let's create protected uh protected array of uh off-roads okay so which will be by default an empty array and right here in the get i just want to type these rows so i can do right here in two ways so for example i can put inside the rows for the given path what is the what's the callback and i'm creating this as an associative array for given path this is the callback but later we are going to create similar function for post and if we do like this we have we might have a different function right here for post so forget it might render the contact form but for post it should handle the submitted data of the contact form right so what i need to do is just to configure forget or for post so i'm going to create a nested area right here specify get so inside the rows the rows basically will look like this so on get it will be an associative array for slash it will be some callback function for slash contact it will be another callback function and in the same way we're going to have a post right here okay i hope this makes sense so i'm going to remove this quickly and right here so we have already configured the rows and now we need to work on the run method so what we need to do right here so on the run basically i'm going to call these rotors resolve okay and this rotor result doesn't exist at the moment so if you're using phpstorm you can just click inside the method hit alt and enter add method and this will create function inside the rotor php for you okay so right here we need to determine what's the current path and the url path basically and what's the current method and based on this from this rows array we need to take the corresponding callback and simply execute and output the result to the user okay so let's do this so we have this super global server for example which contains all the information we need so i can dump this and show this to you so let's open the browser reload and here is our super super global server and right here we have a couple of information and what we need is that path which is displayed right here slash users so the request yuri is basically what we want scroll down we have path info as well and if we just delete everything and just access on the root domain so in this case request ori is slash but path info basically disappears it's not there okay so let's test one more case slash users question mark id equals something we will need these kind of urls as well in the framework right so in this case the path info basically points to whatever we want slash users but the request yuri returns with question mark id equals one as well so in best case we need to take the path info and if the path info is not presented in the super global server we can assume that it is the slash okay so we can do like this to determine the current url but later when we uh take this our um our framework and create a virtual host for this and for locally or for production environments the apache basically doesn't have this path info super global at least in my case uh when i tried on my xampp installation when i tried to do this with the path info apache didn't read that path info it didn't have that path info maybe that's created by this php's built-in server which is started right right here um and let's do it differently and let's take this request jury basically and take everything before the question mark okay to make sure that our mvc framework will work in different environments in apache or in production okay so let's come right here and we have to take the request here and basically i'm going to create right now a request class and i don't want to interact directly to the super global server so i'm just going to quickly create request class in the same in the core folder php store automatically took the namespace and in the request class i'm going to create a couple of functions so get path which will do something we need get method and later we will need also get body to take all the all the data get or pulse data for get path we need to take this request yuri and take everything before the question mark okay so let's take the uh path for example which is from the server to take the request jury if the request yuri is not presented in the path we can assume that it's false okay for some reason that we shouldn't have any kind of error so or we can assume that it's the slash okay the main domain now we we need to check um if question mark is presented in this or not okay so basically i'm going to create a variable position which is str pause give the path and give the question mark so it basically searches this question mark in this path and allocates its position where it is and the position will be false if there is no question mark in the url okay and we can dump this right now and have a look so position let's go to the rotor and right here we need to um we need to access the request class instance what we what we just created so i'm going to create in the application i'm going to create right now the another property which will be for request basically such kind of classes like request router maybe database session should be part of the application so that we can access them anywhere from our framework and call some methods and get some data okay so i'm going to create right here public property request request and i'm going to create an instance of the request right here as well this request is new request okay and i i need to access the request instance from the router what i can do is that i can pass this request instance as a constructor inside the rotor okay so first let's declare the request and then take the request instance and pass it to the rotor so now if we open the rotor class we need to create right here a property for request just like we did in the application okay so i'm going to copy this go to the rotor create property right there and generate basically constructor so i'm going to hit alt and insert on my php storm scroll uh come down to the constructor hit the enter and i'm going to choose only request property i want to generate constructor with the request property and here we have it okay now i can access in this resolve this request and i can call getpath on this request and this get path basically war dumps something at the moment so let's have a look refresh and here is the position of the question mark which looks good if we just remove this now the position is basically false and we need to check like this if position equals to false this means that we don't have question mark in the url and we can immediately return the path this is the final path okay so however if there is the question mark then we need to take the actual path in this case path equals to take the sub string from the given path from position zero until the position of the question mark which is saved in a variable of position okay in this case this should be the path and we can immediately return that path now if we go to the rotor and assume that this is the path and we can dump this path we should see it correctly we need to test every single component every single method what we do very carefully so right here we have slash users which is correct if we just type question mark id equals one hit the enter the path is slash users which looks good if we just remove everything and live on the main domain the path is a slash this looks already good so we have path and we need also method okay method is this request get method okay this get method right now is not implemented it doesn't return anything so let's go there and i'm going to return from the super global server oops server let's take the request method okay which will be gate or post and i'm going to convert this into lowercase str to lower and this will simply be get imposed in a lower case okay right now i can dump this method there as well and it will be get your post in the lower case so i'm not going to do this because it looks very simple so now from these roads for the given method we need to take what is the callback okay so callback equals from these roads for the given method i want to take a callback for the given path okay we have method we have path so we just can take the callback however and we can dump this callback and we can have a look as well however if it is not presented if we just refresh it we see that is this is a closure object and the closure is basically a callback function which we can execute however if i just type some url right here slash users for example hit the enter we're going to have an error because for method get there is no callback for users simply doesn't exist so we can dump the whole roads right here just to clearly understand what's going on so this is how my get looks like on inside the get on slash this is the function on slash contact this is the function and we don't have any function on users so we should not have such kind of such kind of errors notice errors when the when we try to access the url which is not there so instead maybe we can use the double question mark which checks if it is set or not and returns the value if it is set however if it is not set there we can assume that it's false and right here we can make a check if the callback is false so we can immediately return or just echo not found okay and when we echo we can exceed or return or do something okay so right now if i just reload the page i see not found so this is page not found we haven't configured this this is this is good however if there is callback we need to execute this callback and we can execute the callback using function call user func and the first argument basically is the callback what we want to execute and this function will return some string if we just have a look in the index.php this returns some string and what we need to do is just output the value which is returned from this callback okay let's just open browser refresh it so we have not found but if we just try to access the home page we see hello world if we just try to access slash contact we see the contact so using this we have successfully implemented already routing in our in our framework so we can configure right here as many get roles as we want and we can navigate between pages and we can see that it actually works all right now i'm going to show you one more thing which is very important to consider so if we just type right now composer json this returns basically every information from my composer json and the end user basically can see this okay it's a very bad practice to have index.php and composer.json at the same level in your project okay instead we should have some classes some files and folders which should not be accessible from the browser okay in this case what we need to do is to create an web accessible folder in some frameworks it's called web ins in others it's called public i'm going to call public and i'm going to move my index.php inside the public okay and open the terminal and right here when we have started this i'm gonna just uh close this go to the public folder navigate there and start the server from there okay now the server is started from the public folder if i just refresh it shows not found because there is no composer json in this public folder there is only index.php and that's the file which basically should be accessible from the browser if we just try to access the home page we're going to have an error because when we move the index php into public we have to configure the a path to the autoload php so i'm just going to go one directory back and it should already work we have uh successfully um yeah the pages are opening basically and we can navigate just like we were doing it before okay now let's go ahead and create a couple of more folders in our project so i'm going to create controllers where we're creating an actual mvc framework so we need controllers we need modules we need views i'm going to also create a runtime folder which very often exists in the frameworks and it's for user generated data some caching files some i don't know pdf temporary pdf files or whatever it is that goes inside the time and finally we're gonna comment and push this of course the the framework on our git and we don't want the user-generated data to be commented and pushed okay cache files for example it should not definitely be commented and pushed or log files everything such kind of files can go inside the runtime and i'm going to create right here a file which is called git ignore and probably you know what this does and i'm going to comment not the comment i'm going to ignore everything with asterisk right here except the git ignore itself okay so we will be actually able to comment and push the runtime folder itself with the git ignore file but not the not the files and folders inside it all right this looks already good we can create one more git ignore file in the root directory hit ignore or i can make an easy and copy and paste okay and in this root git ignore i'm just going to ignore the vendor folder because that should not be commented and pushed whenever you run composer update or composer install it will generate the vendor folder and i'm gonna also ignore the edr which is the idea folder which is the configuration folder for my php store okay awesome now let's implement actual views so if we just open the index.php and have a look right here we have function on contact as well but contact actually can be a very large form and we don't want to hard code html forms inside this contact uh string right we want to have a view for this so now i'm going to improve my routing and right here instead of having a function i'm going to assume uh contact okay i'm going to write there just contact and what i want to implement is that the router basically will have a look in the views folder it will try to allocate there uh excuse me uh this should be a file contact um let me create contact php and it should actually uh return and contact the the content of this so i'm gonna right now just write h1 okay let me close the php opening tag and inside the h1 i'm just going to write contact okay and i have to implement now that on slash contact this view to be rendered from the views folder okay if i just right now try to access the contact we have such kind of error called user function expected parameter 1 to be valid callback but function contact not found okay so let's go to the rotor and right here when we call this uh call user func we just need to check if the callback is a string i'm gonna use the method is string the callback in this case i'm going to assume that this is this is the view file and i'm going to render this so i'm going to just uh write actually i'm going to change one more thing so instead of like always echo something from here i'm going to return always i'm going to remove this exit i'm going to return from here as well and i'm going to return here as well this render render view this function doesn't exist so we're going to create and i'm going to pass there callback okay this render view so let's create this render view pop f before i actually implement this render view because we change this into return we won't have any output at the moment okay so if we just have a look on the slash contact for example it doesn't do anything because this doesn't do anything because this render view is not implemented but if we just try to access on the home page which should actually output hello world this doesn't work because we are returning some value and this resolve is called from the application so we need to go to the application and echo whatever is returned from this result okay so in this case i have echo written in one place only not in a multiple place so let's just reload the browser we see hello world we won't see anything on the contact and we need to implement this okay right here in this render view we accept the view and i want to render this view and how how can i do this so i'm going to include this view right here okay and i can just specify that i want to include and render this view and from the current current file the core for example i want to go uh one directory back or let's just use the magic constant dear okay i want to go one directory back go inside the views and render contact dot php not contact obviously but the view php so i'm gonna so i'm basically going to change the single quotations into double quotations so that i can inject this view variable right here okay so vue.php this is the file i want to include and right now if i just open the browser it should already print the contact inside h1 you see how big this is and we can view the page source and here is the h1 however so we cannot actually work with this approach in a real emc framework okay we need to also consider the layouts and sometimes we want to pass some values some variables inside the views right so let's implement this step by step and right now i'm going to create a home php and i basically want this home php with the layout so i'm going to use bootstrap because it's very easy and nice so get bootstrap.com i'm going to go to the documentation scroll down grab this starter template and put it right here in the home and we can write the hello world as it is right right now let's open this index.php which is the entry script and i'm going to change this into home okay so this will work i didn't do anything magic right here so we have this hello world but with the actual full html and we have slash contact however however if i just copy and paste right now this in the contact so we are duplicating something so i can write here uh contact um contact us for example but we are duplicating couple of code so we are duplicating the head and the down below the the body script text and so on so we have them written twice in the home php and contact php although it's working fine we can navigate between these two pages so we have this problem and i'm going to also copy a navbar html so let's search for navbar scroll down and take the whole navbar and put it right here above the h1 tag okay format the code and i want to leave right here home slash home slash contact which will have text of contact and i'm going to delete everything else what it is right here okay so including the form so this this is basically how the navbar will look like if i just don't delete this and i just want home and contact nothing else okay so let's go to the home page so let's save this and refresh and i did this for the home page so let's go to the home page oops so and right here we have this number so i'm going to zoom out slightly 100 pixel 100 and here we have contact and home however we need this nav bar inside the contact as well and right here we are basically getting more and more stuck okay we don't we're repeating a lot of html which shouldn't be done of course so i'm going to create right here a folder for layouts and inside the layouts i'm going to create a file which is called main layout why i'm doing doing this so later we're going to implement multiple layouts not only single one but multiple layouts as well okay so you probably have seen that on some websites you have a layout with the sidebar and without the sidebar with the nav bar and without the nav bar and so on and we need to do like this as well so i'm going to open the home copy everything from home and actually cut everything from home go to the layouts and paste everything right here so what i need to do is to create a placeholder where the content should be outputted the page content so right here instead of hello world i'm going to create a placeholder just like this and i'm going to call the placeholder content okay so this is where the actual page content should be outputted okay so let's go to the home and right here i'm just going to have h1 with home i'm going to go to the contact i'm going to have h1 as well right here contact us and whenever we try to render contact vh1 will be injected right here in this area and the same thing will happen for the home page okay right now it's not implemented so we have to do this so let's go to the uh rotor and right here when we render view we want to render view inside the layout okay so i'm gonna right now create another method which will simply return the layout content okay so layout content equals this layout content method okay so let's create this layout content or i can easily do this alt enter enter once again and that can be protected okay protected function layout content and i want to render the layout so how i do this so i can actually include once the layout just like i'm including the view file with the deer but we need to consider a couple of couple of more things okay first of all we are using magic constant d right here going one directory back and doing things like this which is not very good solution so we need to store somewhere in the application what is the root folder of the project of the framework okay so if we just open this index.php right here we know that this index.php will always be inside the public okay and we can assume that the root directory for this project will be i'm going to dump this dear name for the current and directory okay the current directory returns a public folder and their name of current directory will return this php embassy framework so if we just have a look in the browser this is the current folder the project's root directory basically and if we have if we save this somewhere then we can access it and instead of putting d right here the magic constant we can use the project's root directory slash views and whatever it is and we can do the same thing for layouts so what i'm going to do right here is to pass this dear name dear into the application constructor right here for this we need to open the application and accept path right here and let's call it root path for example and we can actually save this as a single tone and we can actually save this as a static property of the application or as an instance of this application okay okay let's save this as a static property of the application self and i'm going to create a static property right here public public static it should be actually string root d let's do like this root directory okay and then i'm going to write self root directory is the root path whatever is this okay we are creating just single instance of the application so we are sure that the constructor won't be called twice it won't rewrite anything so we have this root directory and right now in the router i can access this root directory with application root directory slash views slash view php and i can do the same thing right here okay so i'm going to copy this paste right here instead of views view php we're going to have views layouts slash main php okay this is the layout but this layout will return some content and we can have a look in the browser right now so this is how it looks like if we just view page source we have the whole layout including this content placeholder and down below we have this h1 hole so we want to take the content of the layout as a string this content and replace the content with the following h1 take okay so i'm going to do like this so i'm going to call a function of start which basically starts the output caching so when we call up start nothing basically is outputted in the browser okay so off start include this then i'm going to call ob get clean which returns the value whatever is already buffered and clears the buffer so we start caching of the output this is included so this is the actual output and then we just return this instead of outputting to the browser and we just clear the buffer and right how right here we will have this layout content and i need to do the same thing for views okay and take its content and replace inside the layout so i'm going to create one more function right here which will be called let it be protected function render only view okay which will take the view and we'll do basically the same thing like we did for the layout views view dot php okay it just renders the view and right here we have the layout content and we're going to have the view content as well which will be this render only view pass the viewer there and then we need to return str replace just search for the content placeholder inside the layout replace it with the view content okay just like this okay and we can return this immediately and let's have a look so we are calling this render view right here so this should already work refresh and here we have home and contact and we have this in the layout so if we just view page source right here scroll down we have this contact us replaced replacing this uh content placeholder basically and we can see the same thing for home scroll down right here we have it okay which is awesome all right now i'm going to do one more thing so if we just try to access non-existing path so we have this not found but if we have a look in the network tab right here and refresh this this returns status code 200 which is not very good because very often when there is not found the browsers basically return with status code 404 and we need to do the same thing right here so i'm going to create a class in the core right here response class and this response class basically will have a function set status code okay which will be an integer of code okay and right here i'm going to call http status response code the code whatever is this so i'm just setting the status code and i want to call that function from the from the router whenever we just print this not found okay i want to access to the response as well so how i do this in the application first of all we have to create this response variable response just like this we have to create also an instance of this response and now i want to access this from the router so i can of course do something similar just like what i did so i'm i can pass the response instance to the rotor as well and actually i want to do like this but there is a second way how how we can do this as well so we should be able to access the application instance the instance which is up right here in this index.php from the whole application okay so that whenever we want we just call an application response or request or rotor and we can just gets call some methods on this okay so in the application constructor and also in the application properties i'm gonna add a public property uh public application up okay and right here i'm gonna set that um actually i'm gonna do i'm gonna make this a static property okay public static application up and i'm gonna set self up equals this okay using this approach in the router i can access the response in the following way application up response set status code 404 okay which will do the thing and we can return the not phone so let's save this and have a look refresh it and here we have it status code not found however just because i'm just passing the request in the constructor it will be good to pass the response as well so i'm going to copy and paste this response variable paste right here and i'm gonna hit alt enter and i'm gonna put this in the constructor as well so i can i have a couple of options right here okay so again generate getter and setter for this property and so on and actually i want to add this in the constructor okay so i don't know if there is an option for this alt and enter add in the constructor i don't see this so i have to do this manually okay no problem so let's just do like this i'm going to remove this up core request okay because the rotor and the request are in the same class we don't need to specify the namespace and i'm going to write here response response and this response is response okay just like this and the response basically something the phpstorm doesn't like something okay what's going on okay yeah it wasn't edited in the uh doc block so now it looks good and down below right here i can call this response set status code this responds set status code not found which will give us the exact same result but with an error so that happens because in the application we just don't pass this response okay save refresh in the browser and we see this not found which looks good okay now it's already time to implement controllers so again let's have a look in the index.php and we have right here home and contact but we have to also first of all we have to render the contact form this is the one thing we're going to do and we need to handle also submitted data and the submitted data needs to be obviously a function it cannot be view okay so i need to duplicate this and right here whenever post request is made on slash contact so i can write here function okay just like i had before but that function might become very large and long and i don't want this actually let me show that this actually works so let's just write handling handling submitted data okay and let's just create this post method okay just like we have get i'm going to duplicate this we need post right here post and post this is as easy okay and this will already work however we need to trigger the uh post from the contact php okay we need form so i'm going to go to the bootstrap again and search for forms i just want to quickly copy and paste the html just don't lose any time so copy the following html paste right here let's format the code and i'm going to remove all these things id4 just to have a minimalistic html okay so what's going on aria okay yeah i'm just gonna clean up everything so we have just type email we have we don't want this help so i'm going to remove this for and id as well okay and just change this into for example subject so when we make a contact this should be subject type should be text and name should be subject and i'm gonna duplicate this four times so we're gonna have an email our email okay that should have a name of email and for simplicity let's just make one more thing which is just body and that should be text area okay so it doesn't need type it needs name to be body and just like this so let's remove this whole thing we just leave the button submit and we have it so let's have a look now so let's go refresh it uh okay just like this and actually one more interesting thing which i just noticed so when we just uh access and not see the not found in a base case we should see this in the same layout just like we are seeing the other pages okay so that i can easily now click to the home page or contact page to go back to existing page from non-existing page okay so let's go let's do this as well so let's go to the rotor and down below when we render this not found which is basically a string we can do we have two options right here okay so like we have render view so we can duplicate this and have a function render content okay and this will be content and this will be basically view content so let's call it directly the same name and just remove this rendering and it will work in the same way okay and right here now i can call this render oops render content and pass right there not found okay and this is now how it will look like so we have this not found in the layout and i can go to the home page or contact page which you whichever i want okay but in other in the real frameworks the not found can be more than just two words right it can be nicely formatted not found page and we have to do this as well so if we just go to the views and right here create for example underscore 404 page okay and we just put right here h1 not found okay and from the rotor we just render the view view underscore 404 okay this is how it will look like not found in a h1 tag but this gives us possibility to apply some html and css on this to make it nice also what i want to do is put everything in the container so i'm going to put right here container and put the content inside it so now if i go to the contact this is how my contact page looks like and whenever i hit this submit it should be submitted with method post okay not with method get so let's go to the form contact php scroll up and right here on the form i'm going to add action to the current string okay i want to submit on the same url on the contact and the method method will be host okay so let's have a look refresh it hit the submit and right here we see handling submitted data and that comes from the index.php right here okay obviously in the real applications we have to take the data right here send an email maybe save in the database so the logic in this function will definitely get larger and larger and that's why we need controllers okay we need a separate place where all the logic will go okay so what i'm going to do here is i'm going to remove this and replace into an array and populate the first and second elements of the array right now but first let's go to the controllers and right here i'm going to create site controller okay it should have namespace as well namespace up backslash controllers okay and we can write here as well up controllers oops okay and inside controller we need um two actually we can have more than uh one method right here at the moment so let me let me show you what i mean so right now i'm gonna just create action um so i'm gonna create yeah action or we can just call it contact okay or handle contact okay so and right here i'm gonna return the the same thing handling submitted data but the main idea right here is that this handle contact should be executed whenever we try to make the post request on the on the contact form okay so how should we do this so first of all let's go to linux php and right here i'm gonna write site controller class this is the first argument and the second argument will be contact as a string okay so this is an array and if we go to the router php scroll down if the callback is string we assume it is a view if it is not a string in this case we have two options it might be the function just like we had it before or it might be array okay and if it is the array and we pass this array to the call user function it will actually work in the same way just like passing a function so this this call user function will try to execute contact method of this site controller class okay so what i want to do right here is to replace this namespace i write site controller right here and up controller site controller use right here and if we just save this and have a look in the browser just refresh it which will resubmit the data so right here we have call user func expects parameter to be valid callback class up controllers site controller doesn't have a method contact that's actually true because i call the method handle contact or so maybe later we can have right here a contact page as well contact and this should be post contact or handle contact data or whatever let's call it handle contact okay so i'm just gonna put handle contact right here and refresh it and here we say we see handling submitted data which comes from this handling submitted data but why i created this contact right here okay so maybe maybe we want to render even if it's a get method maybe we want to render view from the controller and why we we might need to do this so what i'm going to do right here is that instead of just passing the view right here i want to pass again the site controller class contact okay and what does this mean this means that i want to on whenever gate method whenever get request is made i want to execute the following function and from here i want to show the contact form okay show contact for let's just have a look in the browser and we see that if we just try to access with the get we see this show contact form so i want to render view from here okay so in the best case i need to be able to render view from here and how i can do this so i can call the application we have the application up okay and the application up has access on the rotor property and the rotor has render view look at this and we just pass contact okay and just like this we are able to render view and why i might need this well because sometimes when we render view we want to pass some parameters for example let's do on the home page so i'm going to duplicate this and let it be home page and right here i'm just going to create params array which will be an associative array where name is for example the code holic okay and what i want to do is to take this params and pass it to the render view okay just like this and later i want to be able to access the home page inside the home php i want to access to the name variable which is passed from here okay in best case i want to write welcome php echo name where welcome the code colleague okay this is what i want this is what is my final purpose and how can i do this so first of all we need to open this render view and accept right here params params which will be an array and we need to pass these params into render only view right here as well and right here inside the render only view we get the params and for making this very clear i'm just gonna dump these params and we can have a look okay so when we render contact we don't pass any params so it's an empty array when we access the home page okay we don't see still anything that's interesting thing why we don't see this anything so render only view okay so let's go to the site controller again so we call aha from the home page we are rendering contact so we just need to render home okay and we want to configure from index.php that on the slash it should call site controllers class home okay just like this now refresh the page and right here i see undefined variable name okay but let's go to the rotor and put this var dump right here and here is the params and i want to create a variable name right here which corresponds to the codolic okay so let's go to the render only view and what i'm going to do is very tricky and interesting so i'm going to iterate over the uh params right here and the param is basically key value here so key and we have value and the key basically is name and the value is the codolic right so i want to put the key right key which is a name string and i want to put one more dollar sign right here okay so if this evaluates so if this let me zoom in so if this evaluates as name in this case this will be evaluated as a name variable okay and the name variable basically equals to the value whatever is this in this using this approach i have name variable declared right here and i can dump this name just like this and have a look and here is the codolic okay and then what happens here is that whenever i include the view file this will be home php in our case the include will see these variables okay and just like this we have home welcome the codeholic okay so this works just like this which is amazing and fine all right now we need to also handle the submitted data okay so we have done this on the home page which looks good but look at this first of all so we are repeating this long line many times so in best case we want to render it in this way this render just this render and nothing else okay we give the home we give the array and it simply renders so how we can do this we have to create a base controller class in the core so i'm going to create right here controller class which will have public function render just render which will accept the view and params oops params with an empty array by default and this will return application up router render view pass view pass per arms and that's it now in the site controller we have to extend our site controller from the controller which is which comes from the up core namespace and we have this render method which is awesome now i'm going to call this render right here as well and here we have it so we did many small things uh just improvements but here we have one interesting problem and whenever we have some errors definitely we need to read the error to understand what's going on and right here the php basically complains that you are using this when not in an object context in the site controllers line 24. so we are using online 24 right here this variable but we don't have an instance of this site controller created and we don't call this home on the instance so why does this happen if we just open the router scroll up right here when we call the call user function this is an array the first element of the array according to linux php is the class second element is the method and this method is called statically using this approach okay so what we need to do right here write an if statement if the callback is array so i'm going to create an instance of the controller instance is new and from the callback i want to take the first the the zeroth element which is the controller name and i'm going to create the instance of the controller with the new keyword in front of it i can put parentheses as well but this doesn't make any change at the moment okay so and this is the instance and i can put the instance back inside the callback on the zero index okay so callback at index 0 is new callback at index 0. and using this approach now if we just dump the whole callback right here we see that it is an instance it is an object okay not class if we just comment this is array and the thing here we have this class as a string but right here we have it as an object and now this call user func will still work in the same way and we now have uh this context right here and the rendering works like a charm okay fantastic now we need to handle the submitted data we we started this many times so and how should we do this so first of all let's go to the uh request okay request class and in the request i want to add a method get body okay and this should return all the data so i can actually i can actually access the data right here of course with super global post but i'm not going to do this and i'm going to also explain why i i'm not going to do this so the post item my the post data might contain some malicious malicious characters right there uh submitted from the user and if we just take the post data we have to sanitize this data we have to make sure that we remove all the invalid symbols from there to make it clean and secure to use and only in this case we need to use and if we have multiple forms like this registration form or login form and contact form and some others we have to uh take the post data in all controller methods and by the way in mvc framework the controller methods are called actions so in the actions we need to take the post data and just sanitize these remove invalid characters and do like this but we we have to do this in multiple places okay if we have multiple forms so it's always better to do this in a single place and this will be the request get body right here i'm going to create a body an array which will be finally returned okay this is the final array and i'm going to write an if statement so if this get method is get okay then we have to iterate over super global get is key value peers and we have to sanitize the data okay so inside the body for the given key i'm going to call filter filter variable okay i'm going to pass right there the variable um the constant basically which i want um no this should be called basically filter input okay and right here i want to pass what kind kind of um input should it be so i'm going to specify input get constant okay i want to filter the input with the get and this is the input key and then i'm going to call filter sanitize special charge constant okay so what this will do it will have a look in the super global get using this constant it will have a look in the following key take the value remove some invalid characters and put it inside the body and using this approach we have secure body data the get data and we have to duplicate and do the same thing for post if method is paused i'm going to iterate over my super global post body key filter input input post right here and the same thing is the same okay the other things so using this approach now i can get the data and let's go to the site controller and now i want to access the request instance okay and do some things actually call this get get body so how i can do this i can call application up request it should be request get body okay but again so this is not very convenient i could i can do it definitely better than this so how should we do so this basically prints the whole body so we can we can make sure that this is what we want and we can just print this and have a look and here we have it if we just open the form and type there some subject and hit the enter here we have all the data but i want to accept a request instance right here in the in the method okay so what's going on right here undefined class request why it's undefined up call request okay this is the class i want to include and the use basically was automatically added right here and now i can call directly on request get body but the thing is that this request variable is not passed to this okay so let's have a look so we have an error too few arguments two function side controllers handle contact and we need to go back to the rotor php and when we call these we need to actually specify the argument request argument okay so call user func accepts third second third and more arguments which will be the arguments of the function of the callback and i'm going to specify right here this request so let's have a look now it works in the same way as it was working before and we actually have the submitted data right in the controller which we can take make some validations and do whatever we actually want okay which is awesome all right now i want to start working on the registration okay so for this we can create a method right here and configure in the index.php or we can create a new controller for this i'm going to actually create new controller for for this call auth controller and this will have this must first of all extend from the core controller then right here we can have two methods logging which will return this render login okay and the second method register which will return this render register okay just like this and we have to open the public index.php and configure the roads right here okay so let's duplicate this and whenever get method is called unlogging it should call auth controllers login method and i'm going to replace this with the use and let's duplicate this actually we need to duplicate this two more times okay so whenever post request is made on the slash login we can actually call the same login method okay and the same thing for register okay right here we call register okay and this is the get this is the post and we can actually make a differentiation whether it's a get or post right here in the controller okay so how we can do this so we can we are accepting right here the request we know this now we have implemented this okay i can write an if statement if the request get method is uh get or or post we can do it differently i'm going to make this even more simpler and create helper functions so let's go to this request class and right here we have this get method and first of all let's i'm going to make a code refactoring okay so if i just click inside the method right click refactor rename i'm going to just call it method okay hit the enter what this basically does that it finds all the references in the project and just renames so we know that we are using right here it was renamed we know that we are using in the rotor right here we it is renamed okay so this works like this so i can hit the ctrl z to undo this and we can have a look that this is get method right here ctrl shift c which will redo the same thing and we have method right here so this is this is kind of three key things what like tips and tricks what you need to know second is that i'm going to create a couple of more functions so is get and what this does this will should do is that this method if this method equals to get this will return true and we can do the same thing for post so is post if this method is post this will return true in the out controller we can just call if the request is post okay we just write here return handle submitted data okay and otherwise we just render the form so now let's have a look so first of all we have we have to create the login and register views so let's go to the views and i'm going to copy and paste the contact and call it login and a few more one more time copy and paste and call it register okay so let's go to the register first so we need uh first name of the registration first name we need a last name email and password okay so last name and right here we can specify also the name last name first name first name email and we need password so let's duplicate this two more times and this will be password right here we're gonna have password as well this should have type of password and this will be confirm password or password repeat okay whatever we want password repeat and this should also have type of password with the name of for example confirm confirm password okay let's actually call this confirm password as well okay we have the registration form we can open this and have a look so let's open the page and actually i'm going to add the login and registration in the nav bar okay so let's open the layouts main php right here we have this navbar and i'm going to duplicate this ul give it a margin left auto and this should be logging on slash logging this should be register on slash register register perfect have a look right here click and here we have it this is contact us which we also need to change register uh create an account perfect so okay i'm gonna make one more thing so i'm gonna take these two form groups um right here i want to create a row inside the row i'm gonna create two columns okay just like this and paste the rows right there so the first name last name email password password confirm we don't want body so we can fully remove this and we have this submit button looks good if i just hit the submit it shows the not found why does this happen so let's open index.php and right here we haven't configured register that's the reason refresh it and here we have handle submitted data perfect so we can actually start working on handling the submitted data right now from the health controller uh but before this so let's implement the second layout so let's say that whenever the login form is open or register form is opened we have a different layout and let's say that we don't have this number anymore i just want to implement the second layout in the system so first of all we have to create a second layout and we can call it for example out okay this is the layout and in the layout i want to remove this nav bar completely and this is how it should look like but from the auth controller i should be able to specify that hey i want to use now out layout and render the content inside the out layout so in a best case i want to have a method this set layout right here and i'm going to specify auth for example and basically do the same thing for registration as well okay and we can actually do exactly like this so i can create a function set layout in the base controller in the core controller right here so let's create public function set layout which will accept the layout and has to do some things right there so how we are using the layout if we open rotor php we are using layout right here layouts main php okay so what i can do is that i can change the layout of the controller but i need to take out this and make a property of the rotor class so if i just make this property of the rotor class i can change it from the controller but i think there is better idea if we just create a protected property maybe right here or let's make it public property let it be public string a layout okay which by default let's say that it is main okay so we have an instance of the controller created in the rotor if we scroll up right here this is the instance of the controller we just created okay and i can take this and set it in somewhere so that later i can access that controller and use that controller's layout property right here in the best case this is the application okay inside the application i'm going to create a property public controller controller controller just like this and i'm going to generate setter for this or i can make it public and just assign it so let me generate etc in any case so alt and enter generate getter and setter for example here is my getter here is my sector and from the router when we create the instance of the controller right here i can set this okay application up controller equals new controller this new whatever is this and now i can access this right here okay so let's just take the layout equals application up controller layout which is the main and we can inject this layout right here okay perfect and in the controller i can set the layout using this layout equals the layout whatever is given so using this approach when out controller is called i set the layout applications the controller's layout changes and the change layout is used right here so let's open the browser open the registration page and using this when not in object context so that this happens again in the auth controller line 33. so this happens because i missed one thing scroll up so when we set this up the application up controller i want to put this back inside the callback at a zero position call back at zero is application up controller which is the instance of the controller right so now if i refresh the page i see the registration page inside a different layout we don't have this number anymore so it's just the registration page so this just is the example that we actually created the second layout if we go back to the home page on the login we actually do the same thing the login is not implemented and it's better to just right there at the moment nothing but logging okay but it's definitely in the out layout as well okay other things the home and the contacts are in the uh in the main layout which is good all right guys that's the end of the first part if you enjoy this so far make sure you hit the like button in the next part we're going to implement models forms and validation
Info
Channel: The Codeholic
Views: 53,502
Rating: 4.9531775 out of 5
Keywords: TheCodeholic, php, learn php, php tutorial, learn php 7, php tutorials, build php mvc, build php mvc framework, Build a php MVC framework from scratch, php mvc framework from scratch, php mvc framework, php mvc for beginners, php custom mvc, php custom framework, build own php mvc, learn php mvc, php mvc framework tutorial, how to build php mvc, how to build php mvc framework, php mvc controllers, php mvc views, php mvc routing, php custom routing, php mvc part 1
Id: GTESlsYTUns
Channel Id: undefined
Length: 83min 20sec (5000 seconds)
Published: Tue Jul 28 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.