Mastering Laravel framework by disassembling its components

Posted August 27, 2014 - 3 min read
Topics:  

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.