Adding multiple Images for an Entity - Step 1 - Creating a database table form to allow for multiple images to be uploaded.

If an entity (a person or an item) needs to have multiple images for each item then you will need an extra database entity and model to store those images. In the following example, we imagine a situation where each member of the tennis club can upload multiple images of themselves. Firstly, we need a new table in the database in which to store the images. Save the following code into a file called database/migrations/createMemberImagesTable.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use App\Models\Member as member;

class CreateMemberImagesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('memberimages', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('memberid');
            $table->foreign('memberid')->references('id')->on('member');
            $table->text('description');  
        });
        DB::statement("ALTER TABLE memberimages ADD imagefile LONGBLOB");
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('memberimages');
    }
}

Once the table has been created, generate crud by scaffolding the table

php artisan infyom:scaffold memberimages --fromTable --tableName=memberimages

Once you have scaffolded the table we need to remove any validation rules which the scaffolder may have generated which require the memberimage to be a string. This happens because the scaffolder isn't sophisticated enough to happen Longblobs and therefore assumes it's a type of string and adds a rule. Whenever you try and upload a file and assign it to the longblob this validation rule will fire and stop you creating the object. To correct this edit the file app/Models/member.php if you see a rule which says the memberimage should be a 'nullable|string' as below - remove the |string to leave just 'nullable'

First add the following setting to the form helper in resources/views/members/create.blade.php. Find the {{ ! Form:open }} helper and add the 'files' => 'true' setting to enable the multipart from data which enable files to be uploaded.

Next, modify the fields function of the MemberImageController as follows so that it takes a single parameter containing the member's id. Any images uploaded will be associated with this id. By passing the memberid to the form it allows us to hide this information on the form when submitting it. This will avoid the user from having to enter this information, improving the usability and removing a potential source of error. To enable this, open the file /app/http/controllers/memberimagesController.php and replace the code for the create function with the following code

public function create($memberid)
{
    return view('memberimages.create')->with('mid',$memberid);
}

Add the following route to routes/web.php

Route::get('member/newimages/{memberid}', 'App\Http\Controllers\memberimagesController@create')->name('member.newimages');

Because the memberid is being passed to the form rather than entered by the user we can replace the <div> which contains the memberid field with a simple a hidden input field which will contain the memberid so that this information will be passed when the form is submitted and we can associate these images with the appropriate member. To do this and to include fields for file upload and description open the file resources/views/memberimages/fields.blade.php view to allow the user to upload multiple images. Open the file and replace the code that you find there with the following code.

<!-- Memberid Field -->
{!! Form::hidden('memberid', $mid, ['class' => 'form-control']) !!}

<!-- Imagefile Field -->
<div class="form-group col-sm-6">
    {!! Form::label('imagefile', 'Imagefile:') !!}
    {!! Form::file('imagefile[]', null, ['class' => 'form-control']) !!}
</div>

<!-- Description Field -->
<div class="form-group col-sm-12 col-lg-12">
    {!! Form::label('description', 'Description:') !!}
    {!! Form::text('description[]', null, ['class' => 'form-control']) !!}
</div>

<!-- Imagefile Field -->
<div class="form-group col-sm-6">
    {!! Form::label('imagefile', 'Imagefile:') !!}
    {!! Form::file('imagefile[]', null, ['class' => 'form-control']) !!}
</div>

<!-- Description Field -->
<div class="form-group col-sm-12 col-lg-12">
    {!! Form::label('description', 'Description:') !!}
    {!! Form::text('description[]', null, ['class' => 'form-control']) !!}
</div>

<!-- Imagefile Field -->
<div class="form-group col-sm-6">
    {!! Form::label('imagefile', 'Imagefile:') !!}
    {!! Form::file('imagefile[]', null, ['class' => 'form-control']) !!}
</div>

<!-- Description Field -->
<div class="form-group col-sm-12 col-lg-12">
    {!! Form::label('description', 'Description:') !!}
    {!! Form::text('description[]', null, ['class' => 'form-control']) !!}
</div>

Notice the [ ] brackets in the name of the fields. This will allow multiple fields with the same name to be uploaded as an array. In this way, you can copy and paste this div tags as many times as you want on the same form. Three images should be enough for each member of my tennisClub but if you wanted more you could simply copy and paste the imagefile[] and description[] form tags and repeated them below as many times as necessary. The controller store() function is designed to process as many files/description combinations as are present.

Now when you visit http://localhost:8000/member/newimages/2 . The number 2 will be passed to the form as a memberid and hidden in the form so it can be passed to the controller. Your form should look something like the one below. 

In a typical website it is more likely that the memberid would be picked up from session data. Members would probably be required to login to the system to upload their own photos. Once a user is logged useful information such as their member id will be stored in the session. See the security section for an explanation of how to do this.

Alternatively, we could add a link on the member/search along with the Edit and Delete links which exists for each member we would have an Add Images link.

Next, we'll modify the createAction() in the MemberimageController to allow us to process a form with multiple image files attached.