This title was written for Laravel version 4. If you're looking for material on the latest version of Laravel, then please check out Code Smart.
It was a cold, dark night in Los Angeles, but the lights of the Dolby Theatre lit the street so bright that you could be forgiven for thinking that it was daytime. You see, the venue had been the setting for the Academy Awards back in February, where the Iron Man movies had won all of the Oscars presented that night for being absolutely, completely, AWESOME.
In fact, if this book sells well, I might buy a mansion in California; perhaps build a super-lab underneath it. There I could work on an exoskeletal suit fashioned in the likeness of a red panda. Unlike Tony Stark, I’d have to leave the supermodels alone. I don’t think Emma would stand for any of that funny business.
I’d call myself ‘The Fire Fox’, and use my powers and gadgets to settle any tabs versus spaces arguments that arise within the PHP community. I’d also have the power of receiving lawsuits from Mozilla. I’d probably not drive an Audi though. Instead, I... well. Sorry, I got a little carried away. Where were we?
Ah yes, the Dolby Theatre. You see, the Oscars were only paving way to a much more high profile event, the Laravel four premiere. PHP developers who had been saved by Laravel 3 gathered by the millions to await the launch of the new framework. Crowds littered the streets, reporters everywhere! Picture it, no really. You will have to imagine most of this, I’m not a fictional writer you see. Just picture it how you see it on the telly.
A long, black stretch limousine approaches the curb. The door bursts open and a tall figure steps out onto the red carpet. The crowd goes wild! Ladies rip off their tops, men rip off each other's tops, reporters rip off their tops, everyone is topless. I don’t know where I’m going with this, but it’s my story, and I say everyone is topless. Anyway, the figure of course is none other than Taylor Otwell, the creator of Laravel.
Before Taylor has taken a step towards the entrance of the theatre he is bombarded with a pack of reporters hungering for the inside scoop on Laravel four. He tries to shove the topless reporters away but there are too many of them.
How long have you been working on Laravel four?
“A year or so now.” says Taylor, realising that his only chance of proceeding would be to answer some of the questions. The topless reporter seems satisfied with having her question answered, and allows Taylor to pass.
Another topless reporter quickly steps in front of Taylor, pouncing with another question.
How long have you been working on Laravel four?
Wait a second. Didn’t he already get asked that? “Not again.” thought Taylor, who hated repeating himself. “About a year.” he said with a stern voice. He pushed forward through the crowd only to have his path blocked by yet another topless reporter.
Laravel is quite a large project. How long did it take you to write it?
Something in Taylor snapped, he reached into his suit pocket and pulled out a keyboard. Taylor is kind of tall, long pockets... oh who cares how the keyboard fit in there, I’m making this up. He struck the reporter across the face with the keyboard, sending the topless chap flying into a nearby dumpster.
“Did you not read the documentation!?” Taylor screamed at the startled reporter, who was struggling to climb out of the greasy dumpster. “I built the form builder so that you can define your forms within templates. If you had all built a form before hand we could have avoided all this repetition. I HATE REPETITION”, snarled Taylor. He spun around and darted for the door where the Laravel team were waiting for him backstage.
Yes. That was all just to build up to the form builder. Don’t look at me so disappointed! I’m a technical writer, not a fictional one. What were you expecting... A Song of Ice and Fire? Right, let’s just get on with it!
This chapter posed a real dilemma. Well, not just this chapter. Let’s see if you can solve the problem better than I can. Here are topics that intertwine.
- Request Data
- Forms
- Validation
You see, they are all big topics, but they also rely on each other. You can’t test the response from a form without knowing how to retrieve request data. You can’t show form repopulation without first teaching validation. It’s a real tangle.
Well, this is how I am going to resolve the problem. We are going to learn how to build forms and target them to framework routes. However, some of our forms explanation will take place in the next chapter, where we will learn how forms can be repopulated after validation.
Let’s get started shall we?
Opening Forms
Before we start submitting data, we need to decide where we are going to send it. We took a look at how to generate framework URLs within the URL generation chapter. We could easily build a form open tag using the skills we picked up from that chapter, right?
Let’s build a simple view:
<!-- app/views/form.blade.php -->
<form action="{{ url('our/target/route') }}" method="POST">
</form>
Here, we use the url()
helper method to provide a framework URL for the action attribute of our form. Let’s also add a routed closure to display our form.blade.php
blade template.
<?php
// app/routes.php
Route::get('/', function()
{
return View::make('form');
});
Great! Now let’s go ahead and visit the /
url to see the source that was rendered. It looks like this.
<!-- app/views/form.blade.php -->
<form action="http://demo.dev/our/target/route" method="POST">
</form>
Our form now has a destination for the data that it collects. This is how I tend to construct my forms, but Laravel is a framework of options. Here’s another method of building form opening HTML that you might prefer. Let’s take a look.
<!-- app/views/form.blade.php -->
{{ Form::open(array('url' => 'our/target/route')) }}
{{ Form::close() }}
To create our opening form tag, we use the Form::open()
generator method. This method accepts only a single parameter, with many parameters. Confused? I’m talking about an array!
In the above example we are using the URL
index, with a value of the route that we wish to be the target of the form. We also use the Form::close()
method to close the form, although I see no reason why you would need to do this. I suppose it looks neater next to the other source generator methods? It’s up to you whether you choose to use it, or </form>
instead.
Here’s the resulting source from our rendered form view.
<!-- app/views/form.blade.php -->
<form method="POST" action="http://demo.dev/our/target/route" accept-charset="UTF-8">
<input name="_token" type="hidden" value="83KCsmJF1Z2LMZfhb17ihvt9ks5NEcAwFoRFTq6u">
</form>
Wonderful, our form has been generated to the same target.
I’m going to ask you to do something really important here, could you please ignore the _token
hidden attribute? Don’t worry, we will come back to it later! For now, I’m going to pretend that it doesn't exist.
Wait, we only provided a URL. Why are there other attributes?
Well done for changing the topic away from the _token
input.
What
_token
?
Great! Well, let’s get back to your question. You see, Laravel knows that POST
forms are the most popular choice when building web applications. For that reason it will use the POST
method by default, overriding the default GET
method that HTML assumes.
The accept-charset
attribute is another useful attribute that Laravel provides for us. It will ensure that ‘UTF-8` will be used for character encoding when submitting the form. It’s a sensible default for most sithations.
Perhaps sensible defaults don’t suit our sithation? What if we want to provide our own?
<!-- app/views/form.blade.php -->
{{ Form::open(array(
'url' => 'our/target/route',
'method' => 'GET',
'accept-charset' => 'ISO-8859-1'
)) }}
{{ Form::close() }}
Here we have used the method
index of our Form::open()
array to specify that we wish to use GET
as the method for our form. We have also used the accept-charset
index to provide a different character set for encoding.
Here’s the new HTML source.
<!-- app/views/form.blade.php -->
<form method="GET" action="http://demo.dev/our/target/route" accept-charset="ISO-8859-1">
<input name="_token" type="hidden" value="83KCsmJF1Z2LMZfhb17ihvt9ks5NEcAwFoRFTq6u">
</form>
Great! While we value Laravel’s opinion on acceptable defaults, we have all the flexibility we need to overrule them. Since we have so much power, why don’t we create a form that uses the ‘DELETE’ HTTP verb as its method attribute.
We know that we can override the form method using the method
array index. Let’s give it a go.
<!-- app/views/form.blade.php -->
{{ Form::open(array(
'url' => 'our/target/route',
'method' => 'DELETE'
)) }}
{{ Form::close() }}
That looks perfect to me, now let’s check out the generated HTML source.
<!-- app/views/form.blade.php -->
<form method="POST" action="http://demo.dev/our/target/route" accept-charset="UTF-8">
<input name="_token" type="hidden" value="83KCsmJF1Z2LMZfhb17ihvt9ks5NEcAwFoRFTq6u">
<input name="_method" type="hidden" value="DELETE">
</form>
Wait, what’s going on there? We didn’t want a ‘POST’ method. What’s the extra input? Oh yes, I remember now. HTML forms are a little dumb. You see, HTML4 will only support ‘POST’ and ‘GET’ methods on forms. HTML5 does support additional methods, but we don’t want to limit our application to browsers that fully support HTML5.
Don’t worry, Laravel has another trick up its sleeve. By providing a hidden input called ‘method’ we can supply a value to represent our non HTML5 compatible HTTP verbs. Laravel’s routing will look at this POST request, see the included ‘method’ data and route to the appropriate action. This will work on both HTML4 and HTML5, isn’t that great?
Remember how we learned how to upload files and retrieve information about them in the last chapter? You might also remember that the form requires an ‘enctype’ attribute of value ‘multipart/form-data’ for files to be uploaded correctly.
Well Laravel provided an easy way of enabling the ‘enctype’ attribute. Let’s see how it works.
<!-- app/views/form.blade.php -->
{{ Form::open(array(
'url' => 'our/target/route',
'files' => true
)) }}
{{ Form::close() }}
By providing a new index named files
with a boolean value of true
, Laravel will add the necessary attribute to allow the uploading of files. Here’s the generated source from the above example.
<!-- app/views/form.blade.php -->
<form method="POST"
action="http://demo.dev/our/target/route"
accept-charset="UTF-8"
enctype="multipart/form-data">
<input name="_token" type="hidden" value="83KCsmJF1Z2LMZfhb17ihvt9ks5NEcAwFoRFTq6u">
</form>
I have formatted the response a little to make it more readable, but I haven’t changed the content. As you can see, Laravel has supplied the correct encoding type on our behalf. Thanks again Laravel!
In the URL generation and routing chapters you may have learned that URLs to named routes and controller actions can be generated using special methods. Let’s find out how we can target these routes and actions using special indexes on the Form::open()
method.
First let’s take a look at how to target named routes. Here’s an example.
<!-- app/views/form.blade.php -->
{{ Form::open(array(
'route' => 'my_route'
)) }}
{{ Form::close() }}
Instead of using the url
index, we use the route
index and provide the name of the route as a value. It’s as simple as that! In fact, it’s just as easy to target controller actions. Let’s take a look at another example.
<!-- app/views/form.blade.php -->
{{ Form::open(array(
'action' => 'MyController@myAction'
)) }}
{{ Form::close() }}
To target our form at a controller action, instead of the url
and route
indexes, we use the action
index and the controller-action pair as its value.
Well, now that we know how to open forms, I think it’s about time that we started adding some fields. Let’s get going!
Form Fields
Forms aren’t very useful unless they provide a means of collecting data. Let’s look at some of the form fields that we can generate using Laravel’s form builder library.
Field Labels
Wait, there’s something else we need other than the fields themselves. We need labels so that people know what values to enter. Labels can be generated using the Form::label()
method. Let’s take a look at an example.
<!-- app/views/form.blade.php -->
{{ Form::open(array('url' => 'my/route')) }}
{{ Form::label('first_name', 'First Name') }}
{{ Form::close() }}
The first parameter of the Form::label()
method matches the name
attribute of the field that they are describing. The second value, is the text of the label. Let’s take a look at the generated source.
<!-- app/views/form.blade.php -->
<form method="POST"
action="http://demo.dev/my/route"
accept-charset="UTF-8">
<input name="_token" type="hidden" value="83KCsmJF1Z2LMZfhb17ihvt9ks5NEcAwFoRFTq6u">
<label for="first_name">First Name</label>
</form>
Great! We should use labels whenever we can to describe our fields. I’ll lead by example by including them with the other field examples within the chapter.
It’s worth noting that we can include other attribute and value pairs within our generated label element by providing a third parameter to the label()
method. The third parameter is an array of attribute and value pairs. Here’s an example.
<!-- app/views/form.blade.php -->
{{ Form::open(array('url' => 'my/route')) }}
{{ Form::label('first_name', 'First Name',
array('id' => 'first_name')) }}
{{ Form::close() }}
In the above example we have added an ‘id’ of value ‘first_name’ to the label element. Here’s the generated source.
<!-- app/views/form.blade.php -->
<form method="POST"
action="http://demo.dev/my/route"
accept-charset="UTF-8">
<input name="_token" type="hidden" value="83KCsmJF1Z2LMZfhb17ihvt9ks5NEcAwFoRFTq6u">
<label for="first_name" id="first_name">First Name</label>
</form>
Brilliant! Well, now that we know how to label our fields, it’s about time to start creating some of them.
Text Fields
Text fields can be used to collect string data values. Let’s take a look at the generator method for this field type.
<!-- app/views/form.blade.php -->
{{ Form::open(array('url' => 'my/route')) }}
{{ Form::label('first_name', 'First Name') }}
{{ Form::text('first_name', 'Taylor Otwell') }}
{{ Form::close() }}
The first parameter for the Form::text()
method is the name
attribute for the element. This is what we will use to identify the field’s value within our request data collection.
The second parameter is an optional one. It is a default value for the input element. Let’s see the source that has been generated by the method.
<!-- app/views/form.blade.php -->
<form method="POST"
action="http://demo.dev/my/route"
accept-charset="UTF-8">
<input name="_token" type="hidden" value="83KCsmJF1Z2LMZfhb17ihvt9ks5NEcAwFoRFTq6u">
<label for="first_name">First Name</label>
<input name="first_name" type="text" value="Taylor Otwell" id="first_name">
</form>
Our input element has been created, along with its ‘name’ attribute and default value. Just like the Form::label()
method, our Form::text()
method can accept an optional third parameter to supply an array of HTML attribute and value pairs, like this:
<!-- app/views/form.blade.php -->
{{ Form::open(array('url' => 'my/route')) }}
{{ Form::label('first_name', 'First Name') }}
{{ Form::text('first_name', 'Taylor Otwell',
array('id' => 'first_name')) }}
{{ Form::close() }}
The truth is, every single one of the input generators will accept an optional array of attributes as a final parameter. They all work in the same way, so I won’t describe this feature in every section. Just keep it in mind!
Textarea Fields
The textarea field functions in a similar way to the text input type, except that they allow multiline data. Let’s see how they can be generated.
<!-- app/views/form.blade.php -->
{{ Form::open(array('url' => 'my/route')) }}
{{ Form::label('description', 'Description') }}
{{ Form::textarea(‘description', 'Best field ever!') }}
{{ Form::close() }}
The first parameter is the name
attribute for the element, and the second parameter once again is the default value. Here’s the form element as it appears in the generated HTML source.
<!-- app/views/form.blade.php -->
<form method="POST"
action="http://demo.dev/my/route"
accept-charset="UTF-8">
<input name="_token" type="hidden" value="83KCsmJF1Z2LMZfhb17ihvt9ks5NEcAwFoRFTq6u">
<label for="description">Description</label>
<textarea name="description"
cols="50"
rows="10"
id="description">Best field ever!</textarea>
</form>
As you can see from the generated source, Laravel has provided some default values, such as the amount of columns and rows for the field. We could easily override these values by adding new values for them to the optional final parameter. I hope you haven’t forgot about the attributes array!
Password Fields
Some things are secret. Actually, you can tell me your secrets if you like. I’m not the type of person who would publish them as jokes in a technical book for extra laughs.
However, if we want our users to be able to type their innermost secrets into our application securely, then we need to make sure that their characters don’t display on screen. The ‘password’ input type is perfect for this. Here’s how you can generate one.
<!-- app/views/form.blade.php -->
{{ Form::open(array('url' => 'my/route')) }}
{{ Form::label('secret', 'Super Secret') }}
{{ Form::password('secret') }}
{{ Form::close() }}
The first parameter for the Form::password()
method is the name
attribute. As always, there is a final optional parameter for an array of additional element attributes.
Here’s the generated source from the above example.
<!-- app/views/form.blade.php -->
<form method="POST"
action="http://demo.dev/my/route"
accept-charset="UTF-8">
<input name="_token" type="hidden" value="83KCsmJF1Z2LMZfhb17ihvt9ks5NEcAwFoRFTq6u">
<label for="secret">Super Secret</label>
<input name="secret" type="password" value="" id="secret">
</form>
Checkboxes
Checkboxes allow for your form to capture boolean values. Let’s take a look at how we can generate a checkbox form element.
<!-- app/views/form.blade.php -->
{{ Form::open(array('url' => 'my/route')) }}
{{ Form::label('pandas_are_cute', 'Are pandas cute?') }}
{{ Form::checkbox('pandas_are_cute', '1', true) }}
{{ Form::close() }}
The first parameter to the Form::checkbox()
method is the field name
attribute, and the second parameter is the field value
. The third, optional value is whether or not the checkbox will be checked by default. The default is for the checkbox to be unchecked.
Here’s the source generated by the above example.
<!-- app/views/form.blade.php -->
<form method="POST"
action="http://demo.dev/my/route"
accept-charset="UTF-8">
<input name="_token" type="hidden" value="83KCsmJF1Z2LMZfhb17ihvt9ks5NEcAwFoRFTq6u">
<label for="pandas_are_cute">Are pandas cute?</label>
<input checked="checked"
name="pandas_are_cute"
type="checkbox"
value="1"
id="pandas_are_cute">
</form>
Radio Buttons
Radio buttons have an identical method signature to that of checkboxes. The difference is that you can use a number of radio input types to provide a method of selection within a small group of values. Here’s an example.
<!-- app/views/form.blade.php -->
{{ Form::open(array('url' => 'my/route')) }}
{{ Form::label('panda_colour', 'Pandas are?') }}
{{ Form::radio('panda_colour', 'red', true) }} Red
{{ Form::radio('panda_colour', 'black') }} Black
{{ Form::radio('panda_colour', 'white') }} White
{{ Form::close() }}
In the above example you will notice that we have a number of radio buttons with the same name attribute. Only one of them will be able to be selected at once. This will allow our users to choose the colour of a panda.
Here’s how our generated source looks when the form view is rendered.
<!-- app/views/form.blade.php -->
<form method="POST"
action="http://demo.dev/my/route"
accept-charset="UTF-8">
<input name="_token" type="hidden" value="83KCsmJF1Z2LMZfhb17ihvt9ks5NEcAwFoRFTq6u">
<label for="panda_colour">Pandas are?</label>
<input checked="checked"
name="panda_colour"
type="radio"
value="red"
id="panda_colour"> Red
<input name="panda_colour"
type="radio"
value="black"
id="panda_colour"> Black
<input name="panda_colour"
type="radio"
value="white"
id="panda_colour"> White
</form>
Select Boxes
Select boxes, or drop-downs, are another way of providing a choice of values to the user of your application. Let’s take a look at how they can be constructed.
<!-- app/views/form.blade.php -->
{{ Form::open(array('url' => 'my/route')) }}
{{ Form::label('panda_colour', 'Pandas are?') }}
{{ Form::select('panda_colour', array(
'red' => 'Red',
'black' => 'Black',
'white' => 'White'
), 'red') }}
{{ Form::close() }}
The Form::select()
method accepts a name
attribute as the first parameter, and an array of key-value pairs as a second parameter. The key for the selected option will be returned within the request data. The third, optional, parameter is the key for a value that will appear as selected by default. In the above example, the ‘Red’ option will be selected when the page loads.
Here’s the generated source.
<!-- app/views/form.blade.php -->
<form method="POST"
action="http://demo.dev/my/route"
accept-charset="UTF-8">
<input name="_token" type="hidden" value="83KCsmJF1Z2LMZfhb17ihvt9ks5NEcAwFoRFTq6u">
<label for="panda_colour">Pandas are?</label>
<select id="panda_colour" name="panda_colour">
<option value="red" selected="selected">Red</option>
<option value="black">Black</option>
<option value="white">White</option>
</select>
</form>
If we want to, we can organise our select box options by category. To enable this option, all we need to do is provide a multidimensional array as the second parameter. The first level of the array will be the category, and the second level will be the list of values just as before.
Here’s an example.
<!-- app/views/form.blade.php -->
{{ Form::open(array('url' => 'my/route')) }}
{{ Form::label('bear', 'Bears are?') }}
{{ Form::select('bear', array(
'Panda' => array(
'red' => 'Red',
'black' => 'Black',
'white' => 'White'
),
'Character' => array(
'pooh' => 'Pooh',
'baloo' => 'Baloo'
)
), 'black') }}
{{ Form::close() }}
We have added a new dimension to our values array. The top level of the array is now split between ‘Panda’ and ‘Character’. These two groups will be represented by ‘optgroup’ element types within the drop-down.
Here’s the generated source code.
<!-- app/views/form.blade.php -->
<form method="POST"
action="http://demo.dev/my/route"
accept-charset="UTF-8">
<input name="_token" type="hidden" value="83KCsmJF1Z2LMZfhb17ihvt9ks5NEcAwFoRFTq6u">
<label for="bear">Bears are?</label>
<select id="bear" name="bear">
<optgroup label="Panda">
<option value="red">Red</option>
<option value="black" selected="selected">Black</option>
<option value="white">White</option>
</optgroup>
<optgroup label="Character">
<option value="pooh">Pooh</option>
<option value="baloo">Baloo</option>
</optgroup>
</select>
</form>
Email Field
The email field type has the same method signature as the Form::text()
method. The difference is that the Form::email()
method creates a new HTML5 input element that will validate the value provided client side to ensure that a valid email address will be provided.
Here’s another example.
<!-- app/views/form.blade.php -->
{{ Form::open(array('url' => 'my/route')) }}
{{ Form::label('email', 'E-Mail Address') }}
{{ Form::email('email', 'me@daylerees.com') }}
{{ Form::close() }}
The first parameter to the Form::email()
method is the name
attribute for our input type. The second parameter is a default value
. As always, and I hope you haven’t forgotten, there’s always a last, optional, array of additional element attributes.
Here’s how the page source for the above example would be rendered.
<!-- app/views/form.blade.php -->
<form method="POST"
action="http://demo.dev/my/route"
accept-charset="UTF-8">
<input name="_token" type="hidden" value="83KCsmJF1Z2LMZfhb17ihvt9ks5NEcAwFoRFTq6u">
<label for="email">E-Mail Address</label>
<input name="email"
type="email"
value="me@daylerees.com"
id="email">
</form>
File Upload Field
In the previous chapter, we learned how to handle uploaded files. Let’s see how we can generate a file upload field.
<!-- app/views/form.blade.php -->
{{ Form::open(array(
'url' => 'my/route',
'files' => true
)) }}
{{ Form::label('avatar', 'Avatar') }}
{{ Form::file('avatar') }}
{{ Form::close() }}
The first parameter for the Form::file()
method is the name
attribute of the file upload element, however, in order for the upload to work, we need to ensure that the form is opened with the files
option to include the multipart encoding type.
Here’s the generate page source.
<!-- app/views/form.blade.php -->
<form method="POST"
action="http://demo.dev/my/route"
accept-charset="UTF-8"
enctype="multipart/form-data">
<input name="_token" type="hidden" value="83KCsmJF1Z2LMZfhb17ihvt9ks5NEcAwFoRFTq6u">
<label for="avatar">Avatar</label>
<input name="avatar" type="file" id="avatar">
</form>
Hidden Fields
Sometimes our fields aren’t meant to capture input. We can use hidden fields to supply extra data along with our forms. Let’s take a look at how hidden fields can be generated.
<!-- app/views/form.blade.php -->
{{ Form::open(array('url' => 'my/route')) }}
{{ Form::hidden('panda', 'luishi') }}
{{ Form::close() }}
The first parameter to the Form::hidden()
method is the name
attribute, I bet you didn’t see that coming? The second parameter is of course the value
.
This is how the generated page source looks.
<!-- app/views/form.blade.php -->
<form method="POST"
action="http://demo.dev/my/route"
accept-charset="UTF-8">
<input name="_token" type="hidden" value="83KCsmJF1Z2LMZfhb17ihvt9ks5NEcAwFoRFTq6u">
<input name="panda" type="hidden" value="luishi">
</form>
Form Buttons
Our forms are no good if we can’t submit them. Let’s have a close look at the buttons that we have available to us.
Submit Button
First up is the submit button. There’s nothing quite like a classic! Here’s how it looks.
<!-- app/views/form.blade.php -->
{{ Form::open(array('url' => 'my/route')) }}
{{ Form::submit('Save') }}
{{ Form::close() }}
The first parameter to the Form::submit()
is the value
, which in the case of a button is the label used to identify the button. As with all of the input generation methods, the button generation methods will accept an optional last parameter to provide additional attributes.
Here’s the generated HTML source code from the above example.
<!-- app/views/form.blade.php -->
<form method="POST"
action="http://demo.dev/my/route"
accept-charset="UTF-8">
<input name="_token" type="hidden" value="83KCsmJF1Z2LMZfhb17ihvt9ks5NEcAwFoRFTq6u">
<input type="submit" value="Save">
</form>
Great! We can now submit our forms. Let’s have another look at an alternative form of button.
Normal Buttons
When we need a button that won’t be used to submit our form, we can use the Form::button()
method. Here’s an example.
<!-- app/views/form.blade.php -->
{{ Form::open(array('url' => 'my/route')) }}
{{ Form::button('Smile') }}
{{ Form::close() }}
The parameters for the Form::button()
method are exactly the same as the Form::submit()
method mentioned previously. Here’s the generated source from the example.
<!-- app/views/form.blade.php -->
<form method="POST"
action="http://demo.dev/my/route"
accept-charset="UTF-8">
<input name="_token" type="hidden" value="83KCsmJF1Z2LMZfhb17ihvt9ks5NEcAwFoRFTq6u">
<button type="button">Smile</button>
</form>
Image Buttons
Instead of a native button, you could use the HTML5 image button type to submit your form. Here’s an example.
<!-- app/views/form.blade.php -->
{{ Form::open(array('url' => 'my/route')) }}
{{ Form::image(asset('my/image.gif', 'submit')) }}
{{ Form::close() }}
The first parameter to the Form::image()
method is the URL to an image to use for the button. I have used the asset()
helper method to generate the URL. The second parameter is the value of the button.
Here's the generated source code.
<!-- app/views/form.blade.php -->
<form method="POST"
action="http://demo.dev/my/route"
accept-charset="UTF-8">
<input name="_token" type="hidden" value="83KCsmJF1Z2LMZfhb17ihvt9ks5NEcAwFoRFTq6u">
<input src="https://demo.dev/my/image.gif" type="image">
</form>
Reset Button
The reset button can be used to clear the contents of your form. It’s used by your application's users when they have made a mistake. Here’s an example of how to generate one.
<!-- app/views/form.blade.php -->
{{ Form::open(array('url' => 'my/route')) }}
{{ Form::reset('Clear') }}
{{ Form::close() }}
The first parameter to the Form::reset()
method is the label that you would like to appear on the button. Here’s the generated source from the above example.
<!-- app/views/form.blade.php -->
<form method="POST"
action="http://demo.dev/my/route"
accept-charset="UTF-8">
<input name="_token" type="hidden" value="83KCsmJF1Z2LMZfhb17ihvt9ks5NEcAwFoRFTq6u">
<input type="reset" value="Clear">
</form>
Form Macros
In the previous subsection we discovered the various form input generator methods. They can be used to save you a lot of time, but perhaps you have a custom type of form input that is specific to your own applications.
Lucky for us, Taylor already thought about this. Laravel comes equipped with a method that will allow you to define your own form generators, let’s see how it works.
So, where shall we put our form macros? Ah I know, let’s make a file called app/macros.php
, then we can include it from within our routes file. Here’s the contents:
<?php
// app/macros.php
Form::macro('fullName', function()
{
return '<p>Full name: <input type="text" name="full_name"></p>';
});
To define a macro we use the Form::macro()
method. The first parameter is the name that will be used by the method that generates our form field. I’d suggest making it camelCase
for this very reason.
The second parameter to the method is a Closure. The value returned from this closure must be the source code required to construct our field.
Let’s create a simple route to show the result from our new form macro. Here it is:
<?php
// app/routes.php
Route::get('/', function()
{
return Form::fullName();
});
Our route is returning the value of the fullName()
method on the Form
class. This isn’t your average static method, it’s a bit of magic that Laravel provides to call our own form macros. The name of the method matches up to the nickname that we gave to our form macro. Let’s take a look at what is returned from the route we just created.
<p>Full name: <input type="text" name="full_name"></p>
As you can see, the result of our Closure has been returned.
What if we want to supply parameters to our form macros? Sure, no problem! Let’s first alter our form macro.
<?php
// app/macros.php
Form::macro('fullName', function($name)
{
return '<p>Full name: <input type="text" name="'.$name.'"></p>';
});
By providing placeholders within our macro closure, we can use their values within our rendered source. In the above example we have added a method to provide a name attribute for our new input type.
Let’s take a look at how this new parameter can be provided.
<?php
// app/routes.php
Route::get('/', function()
{
return Form::fullName('my_field');
});
Well, that was easy wasn’t it? We just pass the value for our parameter to the magical method that Laravel has provided for us. Let’s take a look at the new result of our /
route.
<p>Full name: <input type="text" name="my_field"></p>
Awesome, the new name value has been inserted into our form field! There’s another great way to avoid repetition. Enjoy!
Form Security
It’s great when we receive data from our forms. It’s what they are there for, right? The trouble is, if our routes can be a target of our own forms, then what’s to stop an external source posting some dangerous data to our site?
What we need is a way of making sure that the data that is sent to us belongs to our own website. Not a problem. Laravel can handle this for us. You should probably know that this form of attack is known as ‘Cross Site Request Forgery’ or CSRF for short.
Now then, do you remember that _token
hidden field that I told you not to worry about? Well now I want you to start worrying about it.
ARGH. We are all gonna die!
Right, well done. Let me explain what this token is. It’s kind of like a secret passphrase that Laravel knows about. It’s been created using the ‘secret’ value from our application config. If we tell Laravel to check for this value within our input data, then we can ensure that the data has been provided by a form that belongs to our application.
We could check for the token ourselves by comparing its value to the result of the Session::token()
method, but Laravel has provided a better option. Do you remember the defaults from our filters chapter? Well, Laravel has included the csrf
filter. Let’s attach it to a route.
<?php
// app/routes.php
Route::post('/handle-form', array('before' => 'csrf', function()
{
// Handle our posted form data.
}));
By attaching the csrf
filter as a before
filter to the route that will handle our form data, we can ensure that the _token
field is present and correct. If our token is not present, or has been tampered with, then a Illuminate\Session\TokenMismatchException
will be thrown, and our route logic will not be executed.
In a later chapter we will learn how to attach error handlers to certain types of exceptions in an effort to handle this circumstance appropriately.
If you used Form::open()
to create the wrapping form markup, then the security token will be included by default. However, if you want to add the token to manually written forms, then you must simply add the token generator method. Here’s an example.
<!-- app/views/form.blade.php -->
<form action="{{ url('handle-form') }}" method="POST">
{{ Form::token() }}
</form>
The Form::token()
method will insert the hidden token field into our form. Here’s the source that will be generated.
<!-- app/views/form.blade.php -->
<form action="http://demo.dev/handle-form" method="POST">
<input name="_token" type="hidden" value="83KCsmJF1Z2LMZfhb17ihvt9ks5NEcAwFoRFTq6u">
</form>
To summarise, unless you want external applications and users to be able to post data to your forms, you should use the ‘CSRF’ filter to protect the routes which handle your form data.
My books are available online for free to encourage learning. However, if you'd like for me to keep writing, then please consider buying a digital copy over at Leanpub.com.
It's available in PDF, ePub, and Kindle format, and contains a bunch of extras that you won't find on the site. I have a full-time job, and I write my books in my spare time. Please consider buying a copy so that I can continue to write new books from the comfort of my sofa!