Laravel5.1表单处理

Published on 2017 - 04 - 10

Creating a User Feedback FormT

Let’s kick things off by building a simple contact form consisting of three fields, including the user’s name, email address, and message (see below figure).

Although we could create a Contact controller expressly for the purpose of displaying and processing the contact form, I prefer to manage this sort of feature in a controller that additionally handles other application-related administrative matters. In the case of TODOParrot this feature is managed by the About controller’s create and store actions (create presents the form via the GET method and store processes it via POST). You’re of course free to manage the contact feature within any controller you please, however because the About controller (which also houses the “About TODOParrot” page at http://todoparrot.com/about) would otherwise not use the create and store actions I decided to consolidate the contact feature there. However I’m only using the RESTful create and store naming conventions for organizational purposes; the About controller only actually contains three actions (index, create and store) and doesn’t concern itself with manipulation of a particular resource. Therefore in this case I suggest creating a “plain” controller using Artisan’s make:controller command:

$ php artisan make:controller --plain AboutController
Controller created successfully.

Next, to route users to the contact form using the convenient /contact shortcut you’ll need to define two aliases in the app/Http/routes.php file:

Route::get('contact', 
  ['as' => 'contact', 'uses' => 'AboutController@create']);
Route::post('contact', 
  ['as' => 'contact_store', 'uses' => 'AboutController@store']);

Next, you’ll need to add the create and store actions to the newly created About controller, because when the --plain option is used in conjunction with Artisan’s make:controller method an empty controller will be created. Modify this controller to look like this:

 <?php namespace todoparrot\Http\Controllers;

 class AboutController extends Controller {

     public function create()
     {
         return view('about.contact');
     }

     public function store()
     {
     }

 }

The create action has been configured to serve a view named contact.blade.php found in the directory resources/views/about. However we haven’t yet created this particular view so let’s do so next.

Creating the Contact Form

 @extends('layouts.master')

 @section('content')

 <h1>Contact TODOParrot</h1>

 <ul>
     @foreach($errors->all() as $error)
         <li>{{ $error }}</li>
     @endforeach
 </ul>

 {!! Form::open(array('route' => 'contact_store', 'class' => 'form')) !!}

 <div class="form-group">
     {!! Form::label('Your Name') !!}
     {!! Form::text('name', null, 
         array('required', 
               'class'=>'form-control', 
               'placeholder'=>'Your name')) !!}
 </div>

 <div class="form-group">
     {!! Form::label('Your E-mail Address') !!}
     {!! Form::text('email', null, 
         array('required', 
               'class'=>'form-control', 
               'placeholder'=>'Your e-mail address')) !!}
 </div>

 <div class="form-group">
     {!! Form::label('Your Message') !!}
     {!! Form::textarea('message', null, 
         array('required', 
               'class'=>'form-control', 
               'placeholder'=>'Your message')) !!}
 </div>

 <div class="form-group">
     {!! Form::submit('Contact Us!', 
       array('class'=>'btn btn-primary')) !!}
 </div>
 {!! Form::close() !!}

 @endsection

This form uses the form builder made available through Laravel’s HTML package. To take advantage of the form-specific tags you’ll need to additionally add the following alias to the config/app.php aliases array:

 'Form'=> 'Collective\Html\FormFacade'

If this is your first encounter with the Form::open helper then I’d imagine this example looks rather scary. However once you build a few forms in this fashion I promise you’ll wonder how you ever got along without it. Let’s break down the key syntax used in this example:

{!! Form::open(array('route' => 'contact_store', 'class' => 'form')) !!}
...
{!! Form::close() !!}

The Form::open and Form::close() methods work together to generate the form’s opening and closing tags. The Form::open method accepts an array containing various settings such as the route alias which in this case points to the About controller’s store method, and a class used to stylize the form. The default method is POST however you can easily override the method to instead use GET by passing 'method' => 'get' into the array. Additionally, the Form::open method will ensure the aforementioned CSRF-prevention _token hidden field is added to the form.

Next up you’ll see the following @foreach block:

<ul>
    @foreach($errors->all() as $error)
        <li>{{ $error }}</li>
    @endforeach
</ul>

This block is used to output any validation errors should one or more of the user-supplied field values not pass the validation tests (more on this in a moment).

Next you’ll see a series of methods used to generate the various form fields. This is a relatively simplistic form therefore only a few of the available field generation methods are used, including Form::label (for creating form field labels), Form::text (for creating form text fields), Form::textarea (for creating a form text area), and Form::submit (for creating a submit button). Note how the Form::text and Form::textarea methods all accept as their first argument a model attribute name (name, email, and message, respectively). All of the methods also accept an assortment of other options, such as class names and HTML5 form attributes.

Once you add this code to your project’s resources/views/about/contact.blade.php file, navigate to /contact and you should see the same form as that found at http://todoparrot.com/contact!

With the form created, we’ll next need to create the logic used to process the form contents and send the feedback to the site administrator via e-mail.

Creating the Contact Form Request

Laravel 5 introduces a new feature known as a form request. This feature is intended to remove form authorization and validation logic from your controllers by encapsulating this logic in a separate class. TODOParrot uses form requests in conjunction with each form used throughout the site and I’m pleased to report this feature works meets its goal quite nicely.

To create a new form request you can use Artisan’s make:request feature:

$ php artisan make:request ContactFormRequest
Request created successfully.

This created a file named ContactFormRequest.php that resides in the directory app/Http/Requests/. The class skeleton looks like this (comments removed):

 <?php namespace todoparrot\Http\Requests;

 use todoparrot\Http\Requests\Request;

 class ContactFormRequest extends Request {

   public function authorize()
   {
     return false;
   }

   public function rules()
   {
     return [
       //
     ];
   }

 }

The authorize method determines whether the current user is authorized to interact with this form. Because we want any visitor to be able to use this form you should just modify the method to return true instead of false:

public function authorize()
{
  return true;
}

The rules method defines the validation rules associated with the fields found in the form. The contact form has three fields, including name, email, and message. All three fields are required, and the email field must be a syntactically valid e-mail address, so you’ll want to update the rules method to look like this:

public function rules()
{
  return [
    'name' => 'required',
    'email' => 'required|email',
    'message' => 'required',
  ];
}

The required and email validators used in this example are just a few of the many available via Laravel’s validation class. In the examples to come I’ll provide additional examples demonstrating other available validators. Additionally, note how you can use multiple validators in conjunction with a form field by concatenating the validators together using a vertical bar (|).

After saving the changes to ContactFormRequest.php open the About controller and modify the store method to look like this:

 ...

 use todoparrot\Http\Requests\ContactFormRequest;

 class AboutController extends Controller {

   public function store(ContactFormRequest $request)
   {

     return \Redirect::route('contact')
       ->with('message', 'Thanks for contacting us!');

   }

 }

While we haven’t yet added the e-mail delivery logic, believe it or not this action is otherwise complete. This is because the ContactForm form request will handle the validation and display of validation error messages should validation fail. For instance submitting the contact form without completing any of the fields will result in three validation error found presented in the below screenshot being displayed:

These errors won’t appear out of thin air of course; they’ll be displayed via the $errors array included in the contact.blade.php view:

<ul>
  @foreach($errors->all() as $error)
    <li>{{ $error }}</li>
   @endforeach
</ul>

You’ll also want to inform the user of a successful form submission. To do so you can use a flash message, which is populated in the store method (“Thanks for contacting us!”). The variable passed into the with method is automatically added to the Laravel’s flash data which can subsequently be retrieved via the Session::get method. For instance you’ll find the following snippet in TODOParrot’s master.blade.php so flash messages can be retrieved and displayed above any view:

@if(Session::has('message'))
    <div class="alert alert-info">
      {{ Session::get('message') }}
    </div>
@endif

Only one step remains before the contact form is completely operational. We’ll need to configure Laravel’s mail component and integrate e-mail delivery functionality into the store method. Let’s complete these steps next.

Configuring Laravel’s Mail Component

Thanks to integration with the popular SwiftMailer package, it’s easy to send e-mail through your Laravel application. All you’ll need to do is make a few changes to the config/mail.php configuration file. In this file you’ll find a number of configuration settings:

  • driver: Laravel supports several mail drivers, including SMTP, PHP’s mail function, the Sendmail MTA, and the Mailgun and Mandrill e-mail delivery services. You’ll set the driver setting to the desired driver, choosing from smtp, mail, sendmail, mailgun, and mandrill. You could also optionally set driver to log in order to send e-mails to your development log rather than bother with actually sending them out during the development process.
  • host: The host setting is used to set the host address of your SMTP server should you be using the smtp driver.
  • port: The port setting is used to set the port used by your SMTP server should you be using the smtp driver.
  • from: If you’d like all outbound application e-mails to use the same sender e-mail and name, you can set them using the from and address settings defined in this array.
  • encryption: The encryption setting specifies the encryption protocol used when sending e-mails.
  • username: The username setting defines the SMTP account username should you be using the smtp driver.
  • password: The password setting defines the SMTP account password should you be using the smtp driver.
  • sendmail: The sendmail setting defines the server Sendmail path should you be using the sendmail driver.
  • pretend: The pretend setting will cause Laravel to ignore the defined driver and instead send e-mail to your application log, a useful option while your application is still under development.

In total you’ll want to change the following config/mail.php settings:

  • Change the driver setting to smtp. This is the default value.
  • Change the host setting to smtp.mandrillapp.com.
  • Change the port setting to 587.
  • Change the encryption setting to tls.
  • Change the from['address'] and from['name'] to reflect the e-mail address and name of the sender.
  • Change the username setting to the Mandrill API username.

Next, open the config/services.php file and update the mandrill array’s secret key to point to your Mandrill API key.

Obviously you won’t really want to embed these values directly into mail.php and services.php; Instead you’ll create environment variables for each of these values, and then update mail.php and services.php to use those environment variables.

Save these changes, and then modify the About controller’s store method to look like this:

 public function store(ContactFormRequest $request)
 {

     \Mail::send('emails.contact',
         array(
             'name' => $request->get('name'),
             'email' => $request->get('email'),
             'user_message' => $request->get('message')
         ), function($message)
     {
         $message->from('jason@example.com');
         $message->to('jason@example.com', 'Admin')
           ->subject('TODOParrot Feedback');
     });

   return \Redirect::route('contact')
     ->with('message', 'Thanks for contacting us!');

 }

The Mail::send method is responsible for initiating delivery of the e-mail. It accepts three parameters. The first parameter defines the name of the view used for the e-mail body template. The second parameter contains an array of data which will be made available to the e-mail template. In this case, the desired data originated in the contact form and is now made available through the $request object. The third parameter is a closure that gives you the opportunity to define additional e-mail related options such as the sender, recipient, and subject. Be sure to check out the Laravel mail documentation for a complete explanation of the Mail::send method’s features.

Finally, you’ll need to create the contact view which contains the email content. I suggest saving this file in resources/views/emails. Per the above example you’ll need to name the file contact.blade.php. For the purposes of this example I created a very simple view that looks like this:

 You received a message from TODOParrot.com:

 <p>
 Name: {{ $name }}
 </p>

 <p>
 {{ $email }}
 </p>

 <p>
 {{ $user_message }}
 </p>

HTML formatting is used because Laravel (unfortunately in my opinion) sends HTML-formatted e-mail by default. You can however override this default to instead send text-based e-mail.

Creating New TODO Lists

Now that you understand how to use form requests, let’s next create the interface and logic used to add a new list to the database. Begin by creating a RESTful controller:

$ php artisan make:controller ListsController
Controller created successfully.

With the controller created we next need to inform Laravel that we’d like to declare the controller as RESTFul. Open app/Http/routes.php and add the following line:

Route::resource('lists', 'ListsController');

Save the changes to routes.php and then open the newly created Lists controller. You’ll find seven actions. For easy reference I’ve pasted in the newly created controller, leaving only the two actions (create and show) we’ll use to add a new list:

 <?php 
   namespace todoparrot\Http\Controllers;

 class ListsController extends Controller {

   public function create()
   {
   }

   public function store()
   {
   }

 }

As a reminder, the create action is responsible for serving the form, and store is responsible for processing the submitted form data.

With the controller created and routes defined, it’s time to create the form.

Creating the TODO List Form

Before creating the form you’ll first need to create the List controller’s create view. Begin by creating a directory named lists, placing it in the directory resources/views. Inside this directory create a file named create.blade.php and add the following contents to it:

 @extends('layouts.master')

 @section('content')

 <h1>Create a New List</h1>

 <ul>
     @foreach($errors->all() as $error)
         <li>{{ $error }}</li>
     @endforeach
 </ul>

 {!! Form::open(array('route' => 'lists.store', 'class' => 'form')) !!}

 <div class="form-group">
     {!! Form::label('List Name') !!}
     {!! Form::text('name', null, 
       array('required', 'class'=>'form-control', 
             'placeholder'=>'San Juan Vacation')) !!}
 </div>

 <div class="form-group">
     {!! Form::label('List Description') !!}
     {!! Form::textarea('description', null, 
       array('required', 'class'=>'form-control', 
             'placeholder'=>'Things to do before leaving for vacation')) !!}
 </div>

 <div class="form-group">
     {!! Form::submit('Create List', array('class'=>'btn btn-primary')) !!}
 </div>
 {!! Form::close() !!}

 @stop

Presuming you’ve reviewed the earlier section regarding the contact form, then most of the form syntax is familiar to you. After creating the form, you’ll need to modify the List controller’s create action to serve the view:

public function create()
{
  return view('lists.create');
}

After saving the changes to the List controller, navigate to /lists/create and you should see the form presented in the below screenshot!

With the form in place and the create action updated, it’s time to create the Form Request class used to validate the submitted form data.

Creating the List Form Request Class

In this section we’ll create a form request that will be used to validate the form data. Begin by creating the form request class skeleton:

$ php artisan make:request ListFormRequest
Request created successfully.

Open the newly created form request class (app/Http/Requests/ListFormRequest.php) and you should see the following contents:

<?php 
namespace todoparrotHttpRequests;

use todoparrotHttpRequestsRequest;

class ListFormRequest extends Request {

 public function authorize()
 {
     return false;
 }

 public function rules()
 {
     return [
       //
     ];
 }
}

As a reminder, the rules method is used to define the validation rules which will be used in conjunction with the form fields. The list name and description are both logically required, so modify the method to look like this:

  public function rules()
  {
        return [
            'name' => 'required',
            'description' => 'required'
        ];
  }

You’ll also want to modify the authorize method to return true instead of false, because at this point in time we’re going to allow anybody to use the form :

public function authorize()
{
  return true;
}

Updating the List Controller’s Store Action

With the other pieces of the puzzle in place, all that remains is to update the List controller’s store action to process the form contents. Of course, ListFormRequest handles the tiresome matter of validation, leaving us to focus solely on what to do with the data should it pass muster. In this instance all we need to do is save the data to the database, as demonstrated in the below revised store method:

 use todoparrot\Todolist;
 use todoparrot\Http\Requests\ListFormRequest;

 ...

 public function store(ListFormRequest $request)
 {

       $list = new Todolist(array(
           'name' => $request->get('name'),
           'description' => $request->get('description')
       ));

       $list->save();

       return \Redirect::route('lists.create')->with('message', 'Your list has been created!'); 
 }

Once the list is saved, user are redirected to the list creation form should they desire to create another.

Updating a TODO List

Users will understandably occasionally wish to change a list name or description, so you’ll need to provide a mechanism for updating an existing list. This feature’s implementation is practically identical to that used for the list creation feature, with a few important differences. For starters, just as RESTful creation requires two actions (create and store), RESTful updates require two actions (edit and update). Open the Lists controller and you’ll see these two action method skeletons are already in place:

  public function edit($id)
  {
  }

  public function update($id)
  {
  }

The edit action is responsible for serving the form (which is filled in with the existing list’s data), and the store action is responsible for saving the updated form contents to the database. Notice how both actions accept as input an $id. This is the primary key of the list targeted for modification. These two actions are accessed via (in the case of the Lists) controller GET /lists/:id/edit and PUT /lists/:id, respectively. If the PUT method is new to you, not to worry because Laravel handles all of the details associated with processing PUT requests, meaning all you have to do is construct the form and point it to the update route. Let’s take care of this next.

Creating the TODO List Update Form and Edit Action

The form used to update a record is in most cases practically identical to that used to create a new record, with one very important difference; instead of Form::open you’ll use Form::model:

{!! Form::model($list, 
  array('route' => ['lists.update', $list->id],
        'class' => 'form')) !!}
...
{!! Form::close() !!}

The Form::model method binds the enclosed form fields to the contents of a model record. Additionally, be sure to take note of how the list ID is passed into the lists.update route. This record is passed into the view like you would any other:

public function edit($id)
{

   $list = Todolist::find($id);

   return view('lists.edit')->with('list', $list);

}

When you pass a Todolist record into the Form::model method, it will bind the values of any attributes to form fields with a matching name. Let’s create the entire form, however before doing so you’ll need to create a new view named edit.blade.php and place it in the resources/views/lists directory. Then place the following contents into this view:

 {!! Form::model($list, array('method' => 'put', 'route' => ['lists.update', $list->id], 'class' => 'form')) !!}

 <div class="form-group">
     {!! Form::label('List Name') !!}
     {!! Form::text('name', null, 
       array('required', 'class'=>'form-control', 
             'placeholder'=>'San Juan Vacation')) !!}
 </div>

 <div class="form-group">
     {!! Form::label('List Description') !!}
     {!! Form::textarea('description', null, 
       array('required', 'class'=>'form-control', 
             'placeholder'=>'Things to do before leaving for vacation')) !!}
 </div>

 <div class="form-group">
     {!! Form::submit('Update List', array('class'=>'btn btn-primary')) !!}
 </div>
 {!! Form::close() !!}

Take special note of the form’s method declaration. The put method is declared because we’re creating a REST-conformant update request. After saving the changes to the Lists controller and edit.blade.php view, navigate to the list edit route, being sure to supply a valid list ID (e.g. http://localhost:8000/lists/2/edit) and you should see a populated form!

In cases where the form used to create and edit a record are identical in every fashion except for the use of Form::open and Form::model, consider storing the form fields in a partial view and then inserting that partial into the create and edit views between the form opener and Form::close method.

Updating the List Controller’s Update Action

With the edit action and corresponding view in place all that remains is to update the update action. In most cases you’ll be able to simply reuse the form request helper created for use in conjunction with the create action, and in this case we’ll go ahead and do so:

   public function update($id, ListFormRequest $request)
   {

       $list = Todolist::find($id);

       $list->update([
         'name' => $request->get('name'), 
         'description' => $request->get('description')
         ]);

       return \Redirect::route('lists.edit', 
         array($list->id))->with('message', 'Your list has been updated!');

   }

Make sure you update the input parameters passed into update to include the ListFormRequest request object. Once saved you should be able to edit existing lists!

Deleting TODO Lists

You typically won’t need to create a form of any sort when deleting a record, however because you’ll typically build this feature into an administration interface alongside facilities for inserting and updating records it seems most logical to discuss the matter of deletion within this chapter. When using RESTful controllers the destroy action is responsible for deleting the record, however this action is by default only accessible via the DELETE method.

 $ php artisan route:list
 +--------+----------------------+---------------+----------------------------+------------+
 | Domain | URI                  | Name          | Action                     | Middleware |
 +--------+----------------------+---------------+----------------------------+------------+
 | ...    | ...                  | ...           | ...                        |   |
 |        | DELETE lists/{lists} | lists.destroy | ...ListsController@destroy |  |
+--------+----------------------+---------------+----------------------------+------------+

This means you can’t just create a hyperlink pointing users to the lists.destroy, because hyperlinks by default use the GET method. Instead you’ll use a form with a stylized button to create the appropriate link, as demonstrated below:

{!! Form::open(array('route' => array('lists.destroy', $list->id), 'method' => 'delete')) !!}
    <button type="submit">Delete List</button>
{!! Form::close() !!}

Notice how the Form::open method’s method attribute is overridden (the default is POST) to instead use DELETE. The form’s route attribute identifies the lists.destroy route as the submission destination, passing in the list ID. When submitted, the user will be taken to the Lists controller’s destroy action, which looks like this:

public function destroy($id)
{

  Todolist::destroy($id);

  return \Redirect::route('lists.index')
    ->with('message', 'The list has been deleted!');

}

Associating Tasks with Categories

As you learned it’s really easy to programmatically associate categories with a list using a many-to-many relationship. To quickly recap, you can associate a new task with an existing list within your project controller like so:

 $list = Todolist::find(1);

 $task = new Task;

 $task->name = 'Walk the dog';
 $task->description = 'Walk Barky the Mutt around the block';

 $list->save();

 // Associate categories 3 and 4 with this list
 $list->categories()->attach([3,4]);

But how might you go about effectively integrating this feature into a web form, as depicted in the below screenshot? The answer is easier than you think. As a bonus I’ll introduce two very useful features you’ll likely use repeatedly when building Laravel-driven forms.

To demonstrate how you might implement this feature, I’ll revise the form used in the earlier section, “Creating the TODO List Form”, adding a few additional fields for inputting several starter tasks:

 {!! Form::open(array('route' => 'lists.store', 'class' => 'form')) !!}

 <div class="form-group">
     {!! Form::label('List Name') !!}
     {!! Form::text('name', null, 
       array('required', 'class'=>'form-control', 
             'placeholder'=>'San Juan Vacation')) !!}
 </div>

 <div class="form-group">
     {!! Form::label('List Description') !!}
     {!! Form::textarea('description', null, 
       array('required', 'class'=>'form-control', 
             'placeholder'=>'Things to do before leaving for vacation')) !!}
 </div>

 <h3>Categories</h3>

 <div class="form-group">
     {!! Form::label('Categories') !!}
     {!! Form::select('categories', $categories, null, 
       array('multiple'=>'multiple','name'=>'categories[]')) !!}
 </div>

 <div class="form-group">
     {!! Form::submit('Create List', array('class'=>'btn btn-primary')) !!}
 </div>
 {!! Form::close() !!}

This newly added bit of code creates a multiple select box containing a list of categories:

{!! Form::select('categories[]', $categories, null, 
  array('multiple'=>'multiple')) !!}

The Form::select method accepts four parameters. The first identifies the name of the field. The second identifies array used to populate the select field’s id and name values for each option. The third field, which in this example is set to null, identifies any options (by ID) that should be selected by default. The fourth field identifies any HTML attributes which should be set. In this example we’re ensuring the user can select multiple values. When rendered to the browser using the above code the multiple select box will look like this:

<select name="categories[]" multiple="multiple">
  <option value="1">Leisure</option>
  <option value="2">Exercise</option>
  <option value="3">Work</option>
  <option value="4">Home Remodeling</option>
  <option value="5">Landscaping</option>
</select>

Next, you’ll need to modify the Lists controller’s create method to retrieve the list of categories used to populate the select field. Because you only want the categories table’s id and name columns, you can use a convenient helper named lists which will create an array from the retrieved data, using the provided two columns for the array values and IDs. Here’s an example executed within Tinker:

[1] > $c = \todoparrot\Category::lists('name', 'id');
// array(
//   1 => 'Leisure',
//   2 => 'Exercise',
//   3 => 'Work',
//   4 => 'Home Remodeling',
//   5 => 'Landscaping'
// )

As of Laravel 5.1 the lists method’s behavior has changed in the sense that it returns a collection instead of an array. You can however ensure lists continues to return an array by chaining the all method, such as \todoparrot\Category::lists('name', 'id')->all().

Admittedly I find it weird you identify the column used for the array value before that used for the index, but in any case the method works great provided you keep this in mind, so all you’ll need to do is retrieve the desired data using the lists method and pass it into the view:

public function create()
{
  $categories = Category::lists('name', 'id');
  return view('lists.create')->with('categories', $categories);
}

Finally, you’ll update the Lists controller’s store action to ensure any desired categories are attached to the newly created list:

 public function store(ListFormRequest $request)
 {

   $list = new Todolist(array(
       'name' => $request->get('name'),
       'description' => $request->get('description')
   ));

   $list->save();

   if (count($request->get('categories')) > 0) {
     $list->categories()->attach($request->get('categories'));
   }

   return \Redirect::route('lists.create')
     ->with('message', 'Your list has been created!');

 }

Note how we first check the categories field to confirm it contains at least one category; if so the attach method is used to associate the selected categories with the newly created list. Of course, if the user is required to choose at least one category then consider encapsulating this validation within the associated form helper.

Uploading Files

I’m currently working on a Laravel 5 application which includes a restricted administration console used to manage products sold through an online catalog. Each product includes a name, SKU, price, description, and image. The image is uploaded using the Form::file helper made available through the LaravelCollective/html package, validated alongside the other form inputs using a Laravel 5 form request, and if valid, stored in a special directory. In this section I’ll show you how to integrate a similar form and upload capabilities into your own application.

Let’s begin with a simplified version of the form used in the project. Again, this uses the LaravelCollective/html package’s form helpers to generate the various form fields:

 {!! Form::open(
   array(
     'route' => 'admin.products.store', 
     'class' => 'form', 
     'novalidate' => 'novalidate', 
     'files' => true)) !!}

 <div class="form-group">
     {!! Form::label('Product Name') !!}
     {!! Form::text('name', null, array('placeholder'=>'Chess Board')) !!}
 </div>

 <div class="form-group">
     {!! Form::label('Product SKU') !!}
     {!! Form::text('sku', null, array('placeholder'=>'1234')) !!}
 </div>

 <div class="form-group">
     {!! Form::label('Product Image') !!}
     {!! Form::file('image', null) !!}
 </div>

 <div class="form-group">
     {!! Form::submit('Create Product!') !!}
 </div>
 {!! Form::close() !!}
 </div>

Specific to the matter of file uploading there are two key characteristics of this form you’ll need to keep in mind when implementing your own uploader:

  • The Form::open method sets the 'files' => true attribute. This results in the form data being encoded as “multipart/form-data”, which is required when files will be included as form data.
  • The Form::file helper is used to generate the file upload control.

When rendered to the browser the form looks like this:

As you can see, the form is submitted to a route named admin.products.store. As is typical of any Laravel 5 application, the submitted form data is first routed through a form request. The validation rules are found in the form request’s rules() method. Here’s an example which validates the supplied image to ensure one is present and that it is specifically a PNG (image file):

public function rules()
{
  return [
    'name'  => 'required',
    'sku'   => 'required|unique:products,sku,' . $this->get('id'),
    'image' => 'required|mimes:png'
  ];
}

You can validate uploads using plenty of other approaches such as ensuring it is a Word document or PDF. See the Laravel documentation for more information. This request is passed into the Admin/ProductController.php’s store method, which looks like this:

 public function store(ProductRequest $request)
 {

   $product = new Product(array(
     'name' => $request->get('name'),
     'sku'  => $request->get('sku')
   ));

   $product->save();

   $imageName = $product->id . '.' . 
     $request->file('image')->getClientOriginalExtension();

   $request->file('image')->move(
     base_path() . '/public/images/catalog/', $imageName
   );

   return \Redirect::route('admin.products.edit', 
     array($product->id))->with('message', 'Product added!'); 

 }

In this action we first save the product, and then process the image. There are plenty of different approaches to processing the uploaded image; I’m keeping this simple and just saving the image using a name matching the product ID, so for instance if the saved product using the ID 42 then the associated uploaded image will be named 42.png. The image name is first created (and stored in $imageName) and then it is moved into the application’s /public/images/catalog directory.

Believe it or not, uploading an image using Laravel 5 is really that simple!

Referene