Nowadays websites have become more complex and tend to reproduce real life cases. It's no longer a matter of just developing a static website that displays your company profile, but you need to create an intelligent, tested and functional software that can interact with your users. This task is not an easy one no matter your level in the field. Due to that, you need to develop some good attitude and workflow which can help you do things the right way in time. You need tools to boost your speed without affecting the quality of your work.
Frameworks are tool boxes that can be at good help in that. Working with a framework has become eminent for any respectable developer today and they are many out there you can easily choose from to jump-start any project.
Why create one myself?
Sometimes you can find it hard to adopt a framework, maybe due to time factor or you may not need to learn another thing else. Also for some simple projects or for a teaching purpose one could like to have a home made framework. I also consider it as an eye-opening steps which will help you see the inner aspect of a framework.
Also if you have been learning Object Oriented Programming(OOP) in PHP these days and you are looking for a use case to apply your skills, this could be a great example.
And upon that you need to Reinvent the wheel as Philip Walton says.
So, in this small tutorial I will try to take you through some few steps you can follow to get a home-made bare bone PHP framework for yourself.
1. First pipe all requests through your application starting point(index.php)
In this step start from creating a .htaccess
file at the root of your project. Place the following code inside:
-
On Apache
RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.+)$ index.php/$1 [L]
-
On nginx
# nginx configuration location / { if (!-e $request_filename){ rewrite ^(.+)$ /index.php/$1 break; } }
Create an index.php
file at the same place as your .htaccess
file. Then enter the following code in your index file:
<?php
if (!isset($_SERVER['PATH_INFO']))
{
echo "Home page";
exit();
}
print "The request path is : ".$_SERVER['PATH_INFO'];
?>
Try it by accessing your application like this:
http://localhost:8000
, http://localhost:8000/
, http://localhost:8000/something
, http://localhost:8000/many/otherthings
The URL might be different from yours. Your URLs may look like
http://localhost/project/something
. What matters is to try the different URIs.
From here you can see that anything you enter goes through your index.php
file, which becomes like a pipe. At that point you can decide to take any decision of how to handle the user's requests.
2. Create folders to host your models, views, and controllers
Add three more folders at the root of your project and name them Models
, Views
, Controllers
. Your project folder should look like:
- myProject
- Controllers/
- Models/
- Views/
- .htaccess
- index.php
3. Handle all requests: Routing
Actually there are many ways and everyone is free to use the technic that fits the most their use case. Let's follow the MVC design pattern which can help us easily have RESTful URLs.
To do so we need to find in the request which part is the controller
, the model
and the view
. In order to get those we need to define a law for our application. That law will be that after the host name
the next section must be a controller, and the following an action/method of the controller, then anything following is going to be considered as parameters of the previous action. What would that look like:
http://localhost:8000/controller/action/param1/param2/paramN
In order to do that, first remove all the code from the index.php
except the PHP opening tag <?php
. Add following code to cut the request into pieces:
$url = isset($_SERVER['PATH_INFO']) ? explode('/', $_SERVER['PATH_INFO']) : '/';
var_dump($url);
Save and try the different URLs we used above.
Note the the first element in the
Array()
is not our controller. Normal because the request URI starts with as/
. And before the/
there is nothing, which is counted asempty
.
Change the $url
like following to get rid of the forward slash"
$url = isset($_SERVER['PATH_INFO']) ? explode('/', ltrim($_SERVER['PATH_INFO'],'/')) : '/';
Now our controller is the first element and we have two possibilities, either the $url
is a slash(/
), in that case we are at the home page, or we have an array, in which case we have at least a controller
and/or an action and its parameters if available.
In the MVC design pattern, the controller takes care of the user actions. Thus we need to call a particular controller every time a request is made. The user's actions are usually determined by the call of URLs while clicking on anchors, or while submitting forms, etc. So our application will be listening to those actions and load the appropriate controller and all actions needed.
So change your index content with this:
<?php
$url = isset($_SERVER['PATH_INFO']) ? explode('/', ltrim($_SERVER['PATH_INFO'],'/')) : '/';
if ($url == '/')
{
// This is the home page
// Initiate the home controller
// and render the home view
require_once __DIR__.'/Models/index_model.php';
require_once __DIR__.'/Controllers/index_controller.php';
require_once __DIR__.'/Views/index_view.php';
$indexModel = New IndexModel();
$indexController = New IndexController($indexModel);
$indexView = New IndexView($indexController, $indexModel);
print $indexView->index();
}else{
// This is not home page
// Initiate the appropriate controller
// and render the required view
//The first element should be a controller
$requestedController = $url[0];
// If a second part is added in the URI,
// it should be a method
$requestedAction = isset($url[1])? $url[1] :'';
// The remain parts are considered as
// arguments of the method
$requestedParams = array_slice($url, 2);
// Check if controller exists. NB:
// You have to do that for the model and the view too
$ctrlPath = __DIR__.'/Controllers/'.$requestedController.'_controller.php';
if (file_exists($ctrlPath))
{
require_once __DIR__.'/Models/'.$requestedController.'_model.php';
require_once __DIR__.'/Controllers/'.$requestedController.'_controller.php';
require_once __DIR__.'/Views/'.$requestedController.'_view.php';
$modelName = ucfirst($requestedController).'Model';
$controllerName = ucfirst($requestedController).'Controller';
$viewName = ucfirst($requestedController).'View';
$controllerObj = new $controllerName( new $modelName );
$viewObj = new $viewName( $controllerObj, new $modelName );
// If there is a method - Second parameter
if ($requestedAction != '')
{
// then we call the method via the view
// dynamic call of the view
print $viewObj->$requestedAction($requestedParams);
}
}else{
header('HTTP/1.1 404 Not Found');
die('404 - The file - '.$ctrlPath.' - not found');
//require the 404 controller and initiate it
//Display its view
}
}
4. Create more pages
Actually what the application does is that whenver you request a URL like http://localhost:8000/about/now
it will go in the controllers folder and look for a controller called about
, look for a method called now
in that controller then use the view object to render the content/page to view. To create a page, you need to create a controller, a model and a view for it. So let's create some pages starting from the home page
.
-
Create a
Controllers/index_controller.php
file and add this code in it:<?php /** * The home page controller */ class IndexController { private $model; function __construct($model) { $this->model = $model; } public function sayWelcome() { return $this->model->welcomeMessage(); } }
-
Create a
Models/index_model.php
file and add this in it:<?php /** * The home page model */ class IndexModel { private $message = 'Welcome to Home page.'; function __construct() { } public function welcomeMessage() { return $this->message; } }
-
Create a
Views/index_view.php
file and add this in it:<?php /** * The home page view */ class IndexView { private $model; private $controller; function __construct($controller, $model) { $this->controller = $controller; $this->model = $model; print "Home - "; } public function index() { return $this->controller->sayWelcome(); } public function action() { return $this->controller->takeAction(); } }
Note that
Views/index_view.php
means create a fileindex_view
in the folderViews
.
Now try the http://localhost:8000
or any url pointing to the root of your project. You should see the welcome message. That's it!
Now let's add an about
page. To create the page you will do the samething we did for the home page.
-
Create a
Controllers/about_controller.php
file and add this code in it:<?php /** * The about page controller */ class AboutController { private $modelObj; function __construct( $model ) { $this->modelObj = $model; } public function current() { return $this->modelObj->message = "About us today changed by aboutController."; } }
-
Create a
Models/about_model.php
file and add this code in it:<?php /** * The about page model */ class AboutModel { private $message; public function __construct() { $this->message = "Welcome to the of PHP MVC framework official site."; } public function nowADays() { return $this->message = "nowadays everybody wants to be a boss."; } }
-
Create a
Views/about_view.php
file and add this code in it:<?php /** * The about page view */ class AboutView { private $modelObj; private $controller; function __construct($controller, $model) { $this->controller = $controller; $this->modelObj = $model; print "About - "; } public function now() { return $this->modelObj->nowADays(); } public function today() { return $this->controller->current(); } }
Now try the http://localhost:8000/about
and http://localhost:8000/about/now
. You should see different messages. That's all!
Conclusion
As you may notice, from this point you can easily make this code very big by adding more modules and functionalities based on your need. You can start by making it cleaner for instance you can use composer to load your classes automatically. You easily add more components from other developers and have a strong base.
This mainly aims at teaching you to get your hands dirty in this aspect of coding. by doing so I am expecting you to get use of OOP, discover a bit how the MVC pattern works, etc.
There are many ways to handle the case, here I have introduced one. When you consider professional framework like Laravel or slim, you can see that the routing is more amazing. Try to get the difference or change your code into something like theirs.
In case you could not follow along, here is my source code, you can download it. Also if you like the tutorial please share with others.
Last updated 2024-01-11 UTC