Extending the Request and Response class in Laravel 4

There has been some confusion about how to extend the Illuminate Request and/or the Response classes.

Because of their importance in handling HTTP requests, these two classes are handled slightly differently than normal classes. I will go over how to extend them and then I will show you a method which favors composition over inheritance.

Extending the Response class

I'll cover extending the Response class first, as it is simpler.

In a typical Illuminate library, there is a class which has the main bulk of functionality for the library. This class will often have a corresponding Facade, which allows developers "easy" access to its methods. This is how we are able to simply call Auth::guest() or Redirect::route().

Illuminate's Response class is Illuminate\Http\Response. Its Facade, Illuminate\Support\Facades\Response, however, is different from most. Instead of extending Facade, it is it's own lonely little class.

That is to say, it's not the "face" of Illuminate\Http\Response - rather, it simply uses the class Response:

# File Illuminate/Support/Facades/Response.php

class Response {

/**
 * Return a new response from the application.
 *
 * @param  string  $content
 * @param  int     $status
 * @param  array   $headers
 * @return Symfony\Component\HttpFoundation\Response
 */
public static function make($content = '', $status = 200, array $headers = array())
{
	return new \Illuminate\Http\Response($content, $status, $headers);
}

Somewhat surprisingly, it doesn't use Illuminate\Http\Response for all of it's responses. It uses Symfony classes for JSON, Stream and Download responses.

So, how do we extend this class? Luckily, it's not that hard! It turns out we don't have to deal with Facades at all, which reduces the complexity.

First, make a class extending the Request "Facade":

<?php namespace Fideloper\Example\Facades;

use Illuminate\Support\Facades\Response as BaseResponse;

class Response extends BaseResponse {
	
	public static function doSomething()
	{
		return new \Symfony\Component\HttpFoundation\JsonResponse(['message' => 'yay!']);
	}
	
}

Second, replace Laravel's Response Facade with your own

Assuming your autoloading will handle this class (see my Laravel Application Library Setup article), your next step is to simply replace Laravel's Response Facade with your own.

Head over to app/config/app.php and add in your Response class in place of Laravel's default:

# file: app/config/app.php

'aliases' => array(

	... other aliases …
	'Redis'           => 'Illuminate\Support\Facades\Redis',
	'Request'         => 'Illuminate\Support\Facades\Request',
	//'Response'      => 'Illuminate\Support\Facades\Response',
	'Response'        => 'Fideloper\Example\Facades\Response',

	… more aliases …

)

And voíla! You can use Response::doSomething() to your hearts content! Yay!

Extending the Request class

The request class is trickier. Extending it is NOT as neat and clean. Here's the issue:

The Request class is used very early in the code Chain in laravel. Let's take a look at that:

Open up public/index.php:

// Comments stripped out:
require __DIR__.'/../bootstrap/autoload.php';
$app = require_once __DIR__.'/../bootstrap/start.php';
$app->run();
$app->shutdown();

Note that bootstrap/start.php is the second file called. Let's look at that file:

// Comments stripped out:
$app = new Illuminate\Foundation\Application;

$env = $app->detectEnvironment(array(

	'local' => array('your-machine-name'),

));

… More stuff …

The FIRST thing that happens is that the Application class is created. Now, inside of Illuminate\Foundation\Application:

public function __construct(Request $request = null)
{
	$this['request'] = $this->createRequest($request);

	… More stuff ...
}

protected function createRequest(Request $request = null)
{
	return $request ?: Request::createFromGlobals();
}

So, the FIRST thing that happens in the Application class is the creation (and "filling") of the Request object. So, we can see that VERY VERY early in the code-chain, we have the Request object being created. Not only is it created, but it's populated with the HTTP requests information (headers, parameters, etc).

This happens before any Events are fired and before any Service Providers or Aliases (Facades) are registered. That means that if we use the convential tools to over-ride core classes in Laravel (usually via a Service Provider), we'll be replacing the applications Request object with a blank, empty one.

I made this mistake - I used a service provider and blindly nuked the old Request object with my own. I even had it call Request::createFromGlobals(), so that mine would still capture the request information. However, this doesn't work. The request ends up being created twice (once in the Application class, another time in my Service Provider). The first time the Request is created, it seems to unset some of the request information (due to security?).

Therefore, our one option is to edit bootstrap/start.php and pass in our own Request class. Here's how:

First, create a Request class

<?php namespace Fideloper\Example\Http;

class Request extends \Illuminate\Http\Request {
	
	public function doSomething()
	{
		echo 'Doing something!';
	{
	
}

Second, inject our Request into the Application when it's created

You may have noticed that the Application::__construct method can take a Request as a parameter. We'll make use of that. Open up bootstrap/start.php:

Replace this:

$app = new Illuminate\Foundation\Application;

With this (use whatever classname is appropriate for you):

// Note that we must call "createFromGlobals"
$request = Fideloper\Example\Http\Request::createFromGlobals();
$app = new Illuminate\Foundation\Application( $request );

The issue I take with this approach is that it's not friendly for Packages. You cannot install a Package that will extend the Request class without requiring a developer to edit bootstrap/start.php. This might be a small gripe, but the culture in PHP is (thankfully) moving towards installable packages, and this is a potential road block towards that.

Composition over Inheritance

Martin Fowler famously wrote "Favor composition over inheritance". This means that you should more-often-then-not use a class within your own libraries, instead of extending that class.

In terms of the above examples, instead of extending Request or Response, consider creating a new class and using the base Request or Response class in your class (Via dependency injection, or using the good-old-fashion new keyword).

This has the benefit of avoiding the above pitfalls, and gives you the opportunity to abstract your added functionality in a way that doesn't tie it directly to Laravel, or any framework.

Here's a code example. I create an interface for my new Request and Response classes, and then I create a Laravel-specific implementation of each. You can then create other framework-specific implementations later down the line if you want, and your package will no-longer be framework-specific!

# File: ResponseInterface.php
<?php namespace Fideloper\Example\Http;

interface ResponseInterface {
	
	public function doSomething();
	
}

# File: LaravelResponse.php
<?php namespace Fideloper\Example\Http;

class LaravelResponse implements ResponseInterface {

	public function doSomething()
	{
		return \Response::make('Do Something!');
	}

}

# File: RequestInterface.php
<?php namespace Fideloper\Example\Http;
		
interface RequestInterface {

	public function doSomething();

}

# File: LaravelRequest.php - this one uses DI
<?php namespace Fideloper\Example\Http;

use Symfony\Component\HttpFoundation\Request;

class LaravelRequest implements RequestInterface {
	
	public function __construct(Request $request)
	{
    	$this->request = $request;
	}

	public function doSomething()
	{
		$somethingHeader = $this->request->header('something');
		
		return $somethingHeader;
	}

}

As mentioned, the above code is composing (using) the Laravel Request/Response classes, instead of extending them. The use of interfaces makes them potentially framework-agnostic, allowing you to implement a class for any situation (use in other frameworks or libraries).

You can see some of this in action in my (WIP) ResourceCache package, which composes both the Request and Response classes in order to deal with HTTP Validation caching.