Post navigation

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:

1

2

3

4

5

6

7

8

9

10

11

<?php

namespaceZizzle\Extensions\Html;

classFormBuilderextends\Illuminate\Html\FormBuilder

{

publicfunctionyourFirstFormMacro($value1,$value2)

{

// congrats!

}

}

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:

1

2

3

4

Form::macro('myMacro',function()

{

// macro here

});

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:

1

2

3

4

5

6

7

8

9

10

11

<?php

namespaceZizzle\Extensions\Html;

classHtmlBuilderextends\Illuminate\Html\HtmlBuilder

{

publicfunctionyourFirstHtmlMacro($value1,$value2)

{

// congrats!

}

}

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:

Like this:

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 ?