Laravel 4: Object Oriented Form & HTML Macros

In an earlier post I talked about how to utilize form and HTML macros to DRY up your views. The one thing I don’t like about these form macros is that they are global code, and it doesn’t really feel like they have a proper home. Sure, we can put that code in our routes.php , or global.php , but it definitely takes away from the object-oriented nature of the framework. Furthermore, any common functionality between macros can only be refactored into a global function rather than a class method.

In this post I’ll discuss how we can refactor that code into classes and load it with a service provider class.

Preparation

In preparation you’ll need a place to store these files. You can choose anywhere really, but a common convention in the Laravel community is to create a folder with the name of your application in the app directory.

So, if your app was called Zizzle (don’t ask) you’d create the folder app/Zizzle . You can then put the classes we’ll create in an Extensions folder, so  app/Zizzle/Extensions , and since the Laravel core namespaces both form and HTML macros under a common namespace, we’ll create another folder within called Html resulting in app/Zizzle/Extensions/Html .

Refactoring Your Form Macros

Let’s create a new home for our form macros under the directory we just created. To do so create a new file at  app/Zizzle/Extensions/Html/FormBuilder.php  and insert the following code:

As you can see it’s very simple. We are just extending the core Laravel FormBuilder class and adding our own macro methods to it. So, rather than adding macros like this:

we simply add a new method to our FormBuilder class with the name we want to give the macro.

Refactoring Your HTML Macros

The process of refactoring HTML macros is much the same. Create a new file located at app/Zizzle/Extensions/Html/HtmlBuilder.php  and add the following code:

Here we are simply extending the core Laravel HtmlBuilder class, and at this point adding HTML macros is the same process as adding form macros.

Creating a Service Provider

Now that we have extended the core Laravel HTML and form macro classes to add our own macros in a clean, object-oriented way, we need to be able to tell Laravel how to access our code. We do this by creating a service provider in order to bind our classes to the Laravel IOC container, which essentially tells Laravel to load instances of our HTML and form macro classes instead of the core Laravel classes. The code is fairly straightforward if you’ve read through the Laravel documentation. Create a new file located at  app/Zizzle/Extensions/Html/HtmlServiceProvider.php and add the following code:

Basically we override the two methods from the core Laravel HtmlServiceProvider,  registerHtmlBuilder and  registerFormBuilder , and within return instances of our newly created classes.

Bootstrap the Service Provider

With the service provider created we need to let Laravel know how to load it. Luckily that’s easy too! Open up  app/config/app.php and add the following line to the  providers array:

And that’s it! With that in place you can officially move your global macro code into classes that extend from the Laravel core and bootstrap that code within the Laravel framework.

If you have any questions please feel free to ask!

  • falzhobel

    No question, just giving you a high-five for the great article. Keep’em coming eh! (I’m Canadian too, no pun intended ;)

    • http://www.moderncognition.com crhayes

      Thanks, I appreciate it!

  • http://www.uberweb.com.au Alex

    nice concise guide. Not sure if it’s required but I had to add my app path the autoload classmap in composer.json otherwise I got class not found errors when running composer update

  • João Alfredo

    thanks for the artical. I found a problem using your registerFormBuilder(). I think the correct use is:

    $this->app->bindShared(‘form’, function($app)
    {
    $form = new FormBuilder($app['html'], $app['url'], $app['session.store']->getToken());
    return $form->setSessionStore($app['session.store']);
    });
    You need set up the session for macros work appropriately.

    • http://joelennon.tumblr.com/ Joe Lennon

      Thanks for this comment. The original post breaks the whole automatic form population of old input and form model binding data. Your snippet fixed this for me.

  • Dave

    I used the idea you had from the earler post with the country select, then found this guide but using the countrySelect in the new mystuffExtensionsHtml all i ended up we the error page Country not in
    ExtensionsHtml message.

    How can I use the countrySelect in this set up?

    • Apemantus

      You’ll need to add the namespace in for the Country model. Either add a use statement at the top or include the fullname space when calling Country.

  • Gabriel Kindermann

    Great guide! How can I retrieve validation errors?

  • Sam

    Perfect! Thank’s a lot for this one… a disturbingly large amount of articles suggest keeping this stuff in the routes file!

  • Brandon Viles

    Why Zizzle?

  • RicardoRamirezR

    Awesome! Great article, thank you!

  • CRONUS

    Hi, I’m new to Laravel and I’m confused. What am I doing wrong to get this error: “Class ‘AeroExtensionsHtmlHtmlServiceProvider’ not found”? See screenshot attached.

    Thanks

  • janusz1200

    Thank You very much! Perfect!

  • filipzelic

    Hi Chris, I’ve updated my app to Laravel 5 and got “Error exception in Macroable.php line 87… Method * does not exist. Do you have any suggestion how should I go about this in Laravel 5 ?