Skip to content
Diego Garcia edited this page Oct 4, 2018 · 13 revisions

Features

Table of Contents

Out-of-the-box integration to Bootstrap and Foundation

Former's power lies in outputting CSS-framework HTML automatically. Former recognizes when you create an horizontal or vertical form, and wraps each field in a control group behind the scenes.

That means that when you type:

Former::select('clients')->options($clients, 2)
  ->help('Pick some dude')
  ->state('warning')

What you actually get is (with Bootstrap):

<div class="control-group warning">
  <label for="clients" class="control-label">Clients</label>
  <div class="controls">
    <select id="clients" name="clients">
      <option value="0">Mickael</option>
      <option value="1">Joseph</option>
      <option value="2" selected="selected">Patrick</option>
    </select>
    <span class="help-inline">Pick some dude</span>
  </div>
</div>

By default Former will use Twitter Bootstrap for its syntax but you can select which framework to use with Former::framework(). For the moment Former supports 'TwitterBootstrap3', 'ZurbFoundation' and 'Nude' (for no framework).

// Turn off Bootstrap syntax
Former::framework('Nude');

// Turn it on again
Former::framework('TwitterBootstrap3');

Here is an example for Foundation:

Former::framework('ZurbFoundation');

Former::four_text('foo')->state('error')->help('bar')

Outputs:

<div class="error">
  <label for="foo">Foo</label>
  <input class="four" type="text" name="foo" id="foo">
  <small>Bar</small>
</div>

Custom Framework

You may also implement your own framework/way of doing this by setting a custom class for Former::framework() Like so:

// Custom framework
Former::framework('CustomNameSpace\YourFramework');

Ties-in with Laravel's Validator

Former provides a magic helper withErrors; if set, it checks for any errors that field might have, and sets the error as an .help-inline.

You may need to use Former differently according to how your code reacts after a failed validation:

If your render a view on failed validation (no redirection)

if ($validation->fails()) {
  Former::withErrors($validation);
  return View::make('myview');
}

If your redirect on failed validation

if ($validation->fails()) {
  return Redirect::to('login')
    ->withErrors($validation);
}

Note that on the last example you never actually call Former, but Former will automatically detect the form errors from Input::old() based on the name of your fields.

To provide help text that is not overwritten with an error message, use {!! Former::text('foo')->blockHelp('Help text') !!}. Former only overrides an element's ->inlineHelp() with the element's error message.

You can disable Former's automatic error fetching in the config or with: Former::config('fetch_errors', false)

Form populating

You can populate a form with the Former::populate function, either by the usual passing of an array of values, like this:

// Will populate the field 'name' with the value 'value'
Former::populate( array('name' => 'value') )

or by passing an Eloquent model:

Former::populate( Client::find(2) )

Former will recognize the model and populate the field with the model's attribute. If here per example our client has a name set to 'Foo' and a firstname set to 'Bar', Former will look for fields named 'name' and 'firstname' and fill them respectively with 'Foo' and 'Bar'.

Alternatively you can also populate a specific field after you've populated the whole form (for a relationship per example) by doing this:

Former::populate($project)

Former::populateField('client', $project->client->name)

For the rest of the form, filling fields is basically as easy as doing ->value('something').

You can also use the results from an Eloquent/Fluent query as options for a select, like this:

Former::select('foo')->fromQuery(Client::all(), 'name', 'id')

Where the second argument is which attribute will be used for the option's text, and the third argument is which attribute will be used for the option's value (defaults to the id attribute).

If you don't specify the second or third arguments, Former will call __toString() on each model to use as the value:

class Client extends Eloquent
{
  public static $key = 'code';

  public function __toString()
  {
    return $this->name;
  }
}

Former::select('clients')->fromQuery(Client::all());

This will use the code field for each option's value, and the Client's name field as each option's label.

Former is also able to populate fields with relationships:

Former::populate(Client::find(2))

// Will populate with $client->name
Former::text('name')

// Will populate with $client->store->name
Former::text('store.name')

// You can go as deep as you need to
Former::text('customer.name.address')

// Will populate with the date from all of the client's reservations
Former::select('reservations.date')

// Which is the same as this ^
Former::select('reservations')->fromQuery($client->reservations, 'date')

// If you're using a text and not a select, instead of listing the
// relationship's models as options, it wil concatenate them
Former::text('customers.name') // Will display "name, name, name"

// You can rename a field afterwards for easier Input handling
Former::text('comment.title')->name('title')

Kudos to cviebrock for the original idea.

HTML5 validation

Modern browsers support instant validation via HTML attributes — no Javascript needed nor script nor polyfill. There are a few attributes that can do that kind of job for you, pattern, required, max/min to name a few.

Former uses a ->rules() function to specify which HTML5 live validation rules to use:

Former::open()->rules(array(
  'name'     => 'required|max:20|alpha',
  'age'      => 'between:18,24',
  'email'    => 'email',
  'show'     => 'in:batman,spiderman',
  'random'   => 'match:/[a-zA-Z]+/',
  'birthday' => 'before:1968-12-03',
  'avatar'   => 'image',
));

This would output:

<input name="name"      type="text"   required maxlength="20" pattern="[a-zA-Z]+" />
<input name="age"       type="number" min="18" max="24" />
<input name="email"     type="email" />
<input name="show"      type="text"   pattern="^(batman|spiderman)$" />
<input name="random"    type="text"   pattern="[a-zA-Z]+" />
<input name="birthday"  type="date"   max="1968-12-03" />
<input name="avatar"    type="file"   accept="image/jpeg,image/png,image/gif,image/bmp" />

Note that you can always add custom rules the way you'd add any attributes.

Former::number('age')->min(18)

Former::text('client_code')->pattern('[a-z]{4}[0-9]{2}')

You can also manually set the error state of a control group if you're using Bootstrap or Foundation. You can use any of the control group states which include success, warning, error and info.

Former::text('name')->state('error')

Files handling

In Former like in Laravel you can create a simple file field with Former::file. What's new, is you can also create a multiple files field by calling Former::files which which will generate <input type="file" name="foo[]" multiple />.

One of the special method is the ->accept() with which you can do the following:

// Use a shortcut (image, video or audio)
Former::files('avatar')->accept('image')

// Use an extension which will be converted to MIME by Laravel
Former::files('avatar')->accept('gif', 'jpg')

// Or directly use a MIME
Former::files('avatar')->accept('image/jpeg', 'image/png')

You can also set a maximum size easily by using either bits or bytes

Former::file('foo')->max(2, 'MB')
Former::file('foo')->max(400, 'Kb')
Former::file('foo')->max(1, 'TB')

This will create an hidden MAX_FILE_SIZE field with the correct value in bytes.

Checkboxes and Radios

Former has support for checkbox and radio groups as well:

// Create a one-off checkbox
Former::checkbox('checkme')

// Create a one-off checkbox with a text, and check it
Former::checkbox('checkme')
  ->text('YO CHECK THIS OUT')
  ->check()

// Create four related checkboxes
Former::checkboxes('checkme')
  ->checkboxes('first', 'second', 'third', 'fourth')

// Create related checkboxes, and inline them
Former::checkboxes('checkme')
  ->checkboxes($checkboxes)
  ->inline()

// Checkbox for multiple options with same name
Former::checkboxes('checkme[]') // like in HTML the "[]" suffix makes it post an array
  ->push(false) // no empty values between the selected option values
  ->checkboxes([
    'label' => ['value' => 147, 'checked' => true],
    'label2' => ['value' => 398, 'checked' => false] // normal check() works only for single value checkboxes
  ])

// Everything that works on a checkbox also works on a radio element
Former::radios('radio')
  ->radios(array('label' => 'name', 'label' => 'name'))
  ->stacked()

// Stacked and inline can also be called as magic methods
Former::inline_checkboxes('foo')->checkboxes('foo', 'bar')
Former::stacked_radios('foo')->radios('foo', 'bar')

// Set which checkables are checked or not in one move
Former::checkboxes('level')
  ->checkboxes(0, 1, 2)
  ->check(array('level_0' => true, 'level_1' => false, 'level_2' => true))

// Fine tune checkable elements
Former::radios('radio')
  ->radios(array(
    'label' => array('name' => 'foo', 'value' => 'bar', 'data-foo' => 'bar'),
    'label' => array('name' => 'foo', 'value' => 'bar', 'data-foo' => 'bar'),
  ))

Important: Former gives you an option to force-pushing of checkboxes. Because browsers do not submit unchecked checkboxes with their POST data, you will likely want to force-push an empty value for unchecked checkboxes. You can change what value an unchecked checkbox possesses in the POST array via the unchecked_value option. This will create a hidden input above each checkbox with the same name as the checkbox, and set its value to the unchecked_value.

Localization helpers

By default, when creating a field, if no label is specified Former will use the field name by default. But Former also tries to translate it automatically. This also applies to checkboxes labels, help texts and form legends. Which means the following:

// This
Former::label(__('validation.attributes.name'))
Former::text('name', __('validation.attributes.name'))
Former::text('name')->inlineHelp(__('help.name'))
Former::checkbox('rules')->text(__('my.translation'))
<legend>{{ __('validation.attributes.mylegend') }}</legend>

// Is the same as this
Former::label('name')
Former::text('name')
Former::text('name')->inlineHelp('help.name')
Former::checkbox('rules')->text('my.translation')
Former::legend('mylegend')

Former will first try to translate the string in itself, ie my.text will return __('my.text') and if that fails, it will look for it in a fallback place. You can set where Former look for translations by changing the following variable: Former::config('translate_from', [boolean]) (defaults to validation.attributes). Note that it must be an array.

Form value precedence

To populate your field, Former set the following priorities to found values:

  • The ->forceValue() method wins over everything – it's a special branch of ->value() created to force a value in a field no matter what happens
  • Next is POST data – if a user just typed something in a field, chances are this is what they want to see in it next time
  • Then any values set via Former::text()->populate(), so you can override any global population on a per-element basis.
  • Then any values set via Former::populate() – that means that if you're editing something or are repopulating with some value, it can be overwritten with forceValue
  • Finally the classic ->value() gets the least priority – it is created for minimum and default field values and thus gets overwritten by population and POST data