4
Php

Extend Input Class in Laravel – 4

There is no Input class in Laravel, instead it uses Request class for any Input::method() calls.

Basically, we extend a class in OOP language to add some extra functionalities to a base (already created) class and in PHP, for example, if you have following class

class BaseClass {
    public function hello()
    {
        echo "Say Hello!";
    }
}

Now, if you need to extend this class then you can simply extend a this class like this way

class ChildClass extends BaseClass {
    public function helloWorld()
    {
        echo "Say Hello World!";
    }
}

So now, ChildClass has two methods, one it’as own and one from it’s base class because it extended the functionality from BaseClass class. It’s simple.

If you don’t want to read the full article and just want to find out the main topic then you may directly jump here.

But, in Laravel, you can’t just extend every core class like this way, it means that, you can extend it same way but you an’t use it normally you use any class in any PHP application because, Laravel uses a different approach to access it’s core classes. In laravel, when you want to call a class method, you basically do something like this

// Get all user input from $_REQUEST
$input = Input::all();

Here, it looks like that, Input is a class and all() is it’s static method but actually, it’s not what it looks like. Actually, Laravel-4 doesn’t use static methods and here is a nice article about it, if you read this article, you can find that, actually Laravel-4 doesn’t use static methods, instead it mimics the static calling behavior. It uses Facade design pattern, when you call a static method, actually much more things happen behind the scene than it appears. So, when we call View::make('hello');, actually, Laravel loads Illuminate\Support\Facades\View class and if you look at this class, you can see something like this

class View extends Facade {
     protected static function getFacadeAccessor() { return 'view'; }
}

This is not the original class for View class, instead it’s a Facade class, through this class and IoC Container, somehow Laravel reaches to it’s original class, which is stored in the vendor folder, where all the other vendors are stored and the path for the original View class is vendor/laravel/framework/src/Illuminate/View/View.php, so to extend the View class, you have to extent the main class from vendor folder mentioned above. Actually, this article is about extending the Input class and it looks like I’m talking about something irrelevant but I think it’s relevant because if you want to extend the Input class, you may think that, there is a class in the vendor folder something like this vendor/laravel/framework/src/Illuminate/Input/Input.php but there is nothing like this. Then the question is, where is the main Input class ? If you look into the Facade of Input class, then you can find the answer, the code may looks something like this

// vendor/laravel/framework/src/Illuminate/Support/Facades/Input.php
class Input extends Facade {
    // other code
    protected static function getFacadeAccessor() { return 'request'; }
}

It returns the request just like Request Facade, which means, when you call Input::all(), actually, you use the Request class and all the methods that we use as Input::method(), we actually use the method from the Request class, which is stored in

vendor/laravel/framework/src/Illuminate/Http/Request.php

So, Input is just a wrapper to separate the methods calls from using Request::method() but if you use Request::all() instead of Input::all(), you’ll get the same result. So, if you want to extend the functionality for Input, you have to extend the Request class.

 

So, how to extend Input class, oops! sorry, actually Request class ?

So, now we know that, there is no Input class, instead it’s Request class, which provides all the methods for Input and to extend the Request class we should know that, Laravel components are typically extended in one of two ways:IoCbindings and the Manager classes. The manager classes serve as an implementation of the “factory” design pattern, and are responsible for instantiating driver based facilities such as cache and session but extending the Request class works a little differently than all other classes. Because it’s such a foundational piece of the framework and is instantiated very early in the request cycle, Taylor Otwell himself mentioned about it in his book titled Laravel: From Apprentice To Artisan. So, to extend the Request class you may first create your own class by extending the base Request class using something like this

// apps/libs/extensions/Request.php
namespace Libs\Extensions;

class Request extends \Illuminate\Http\Request {
    // code goes here
}

I have put my class in apps/libs/extensions folder but you may put it where you like. Once you extended the class, open the bootstrap/start.php file. This file is one of the very first files to be included on each request to your application. The first line of code in this file is

$app = new Illuminate\Foundation\Application;

Which creates an instance of Illuminate\Foundation\Application and inside this class, you can see something like this

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

When any application is instantiated, it creates a new Illuminate\Http\Request instance and it happens before any Events are fired or any Service Providers or Aliases are registered. So, instead of using the conventional way to extend and use it via service provider we should extend it normally we did in the example given above and after extending the class we can just replace the following line in the bootstrap/start.php file

$app = new Illuminate\Foundation\Application;

with this two lines of code

$request = Libs\Extensions\Request::createFromGlobals();
$app = new Illuminate\Foundation\Application( $request );

Once we are done with this, we have to add "app/libs/extensions" in our composer.json file, in classmap array of autoload section something like this

"autoload": {
    "classmap": [
        "app/commands",
        "app/controllers",
        "app/models",
        "app/database/migrations",
        "app/database/seeds",
        "app/tests",
        "app/tests/TestCase.php",
        "app/libs/extensions"
    ]
}

Finally, from the console, execute composer dumpautoload and you are done. Well, recently I’ve answered a question on StackOverflow and question was to use Input::only method with wildcard, like $actInputs = Input::only('act*'); which should return all the inputs whose name begins with act such as acting, actor etc and after answering that question I’ve extended the functionality of Input or say Request, so here is the full code of my extended class


Use of new methods in Input or Request class

// return inputs that starts with f (first_name, fathers_name)
$inputs = Input::inputStartsWith("f");
// return inputs that ends with _name (first_name, last_name)
$inputs = Input::inputEndsWith("_name");
// return inputs that matches digit at the end (name1, name2 etc)
$inputs = Input::InputMatching("/^.*\d$/");

I've extended and tested it on my local Laravel installation and works just fine. Hope it could be helpful.

Latest Blog

0
Php

PHP – 8.0 Match Expression

In PHP 8.0 there is a new feature or I should say a new language construct (keyword) going to be introduced,  which has been implemented depending […]