Mastering Laravel framework by disassembling its components
Posted August 27, 2014 - 3 min read
Topics:
php
laravel
framework
Having always a big interest in looking how different frameworks are written, Laravel has attracted me, for being an excellent tool for implementing micro-services and REST APIs.
Within this post, we will discuss building a minimalist framework from scratch based on illuminate components and composer.
As you know, the author of Laravel have already published a micro framework out of Laravel, which is called Lumea.
We will not discuss all illuminate components, because it would be a time-consuming task, and a single post would not be enough.
However, I decided to share with you a minimalist skeleton that can help you understand how Laravel works from inside.
Only basic components necessary to process a request and send back a response will be discussed.
In my next coming posts, I will share with you my experience of developing the rest of the framework.
HTTP request Handling
The very beginning of building any framework is: routing and dispatching a request! For that we need to use three components:
Illuminate/container
As the name suggests, is an implementation of the IoC Container. I have already discussed what are containers and how they can be used in my previous post.
Please take a look if you are interested.
Actually \Illuminate\Foundation\Application
class is simply a container where different components of Laravel are registered.
<?php
namespace Illuminate\Foundation;
//...
class Application extends
Container implements ApplicationContract, HttpKernelInterface {
}
As we are learning how Laravel works, we are not going to use the illuminate\foundation component.
It does a lot of work behind the scenes that we should be aware of.
Illuminate/routing
It’s the routing component. This component is required to route a HTTP request to a controller.
Illuminate/events
Laravel’s events provides a simple observer implementation, allowing you to subscribe and listen for events in your application.
Furthermore, the events component is an essential part of the framework.
Events are a required dependency of the routing component as well as of others core components.
Let’s create a composer.json file where we can include these components:
{
"name": "myapp/laravel-from-the-beginning",
"description": "A tiny framework based on Laravel components",
"require": {
"illuminate/container": "~5.2",
"illuminate/events": "~5.2",
"illuminate/routing": "~5.2"
},
"require-dev": {
},
"license": "MIT",
"autoload": {
"classmap": [
],
"psr-4": {
"App\\": "app/"
}
}
}
Application structure
Our starting application structure should be very minimal.
Remember we are learning how Laravel works, no extra files, configs, dirs are needed. Here is my initial application structure:
app/
http/
controllers/
HomeController.php
public/
index.php
composer.json
Front controller
The front controller is actually our public/index.php file.
<?php
if ( ! file_exists(__DIR__ . '/../vendor/autoload.php')) {
throw new Exception("Autoload file not found.");
}
require __DIR__ . '/../vendor/autoload.php';
$debug = getenv('DEBUG_MODE');
if ( $debug == 1 ) {
error_reporting(E_ALL);
ini_set('display_errors', 1);
}
$app = new \Illuminate\Container\Container();
\Illuminate\Container\Container::setInstance($app);
\Illuminate\Support\Facades\Facade::setFacadeApplication($app);
$app->instance('app', $app);
$app->instance('Illuminate\Container\Container', $app);
/**
* Register events
*/
$app->singleton('events', function ($app) {
return new \Illuminate\Events\Dispatcher($app);
});
/**
* Register router
*/
$app->singleton('router',function ($app) {
return new \App\Routing\Router($app['events'], $app);
});
/**
* Define routes
*/
$app['router']->get('/', '\App\Http\Controllers\HomeController@index');
/**
* Dispatch the request
*/
try {
$request = \Illuminate\Http\Request::capture();
$app->instance('\Illuminate\Http\Request', $request);
$response = $app['router']->dispatch($request);
$response->send();
} catch (\Exception $e) {
if ($debug) {
throw $e;
}
echo "An error occurred!";
}
Controllers
All controllers should be an instance of Illuminate\Routing\Controller.
Let’s create a simple controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
class HomeController extends Controller
{
public function index()
{
return 'Hello world!';
}
}
Conclusion
This was my first attempt to build a working skeleton as a foundation for a micro framework!
Through the time I did lots of refactoring and integrated many components.
In fact, there are many more layers we need to integrate, like middlewares, service providers, the view, error handling, etc., but I think this is pretty a good start.