1

I am trying to work out the best way to do something. I have a form with a lot of fields, including a file input which allows multiple files to be uploaded.

All of this is linked to the model/form ReportingDoc

{!! Form::model(new App\ReportingDoc, [
    'class'=>'form-horizontal',
    'route' => ['projects.reportingDoc.store', $project->id],
    'files' => true
]) !!}

<div class="form-group">
    {!! Form::label('workType', 'Work Type:', array('class' => 'col-sm-5 control-label blue')) !!}
    <div class="col-sm-7">
        <select class="workType" name="workType">
            <option value="recurring">Recurring</option>
            <option value="adHoc">Ad-hoc</option>
        </select>
    </div>
</div>

//Lots of other inputs

<div class="form-group">
    {!! Form::label('filePath', 'Supporting Documents:', array('class' => 'col-md-5 control-label green')) !!}
    <div class="col-md-7">
        {!! Form::file('filePath[]', array('multiple'=>true)) !!}
    </div>
</div>


<div class="form-group">
    {!! Form::submit('Save Data', ['class' => 'btn btn-primary']) !!}
</div>

{!! Form::close() !!}

The model looks like the following:

class ReportingDoc extends Model
{
    protected $table = 'reporting_doc';
    protected $guarded = [];

    public function project()
    {
        return $this->belongsTo('App\Project', 'projectId');
    }
}

So the model belongs to a Project. At the moment, the migration looks like the following:

public function up()
{
    Schema::create('reporting_doc', function(Blueprint $table)
    {
        $table->increments('id');
        $table->String('workType')->default('');
        //all my other inputs
        $table->String('filePath')->default('');
        $table->timestamps();
    });

    Schema::table('reporting_doc', function (Blueprint $table) {
        $table->integer('projectId')->unsigned()->default(0);
        $table->foreign('projectId')->references('id')->on('projects')->onDelete('cascade');
    });
}

In the controller for this route, I have my store method. At the moment it looks like the following:

public function store(Request $request, Project $project)
{
    $workType = Input::get('workType');
    //Other inputs
    $projectId = $project->id;

    $reportingDoc = new ReportingDoc();
    $reportingDoc->workType = $workType;
    //Other inputs
    $reportingDoc->projectId = $projectId;
    $dsReportingDoc->save();

    return Redirect::route('projects.reportingDoc.create', $project->id)
        ->with('message', 'Files uploaded.');

    /* Old part
    $files = Input::file('filePath');
    $file_count = count($files);
    $uploadcount = 0;

    if(isset($files)) {
        foreach($files as $file) {
            $destinationPath = public_path() .'/uploads/';
            $filename = $file->getClientOriginalName();
            $upload_success = $file->move($destinationPath, $filename);
            $uploadcount ++;
        }
    }

    if($uploadcount == $file_count){
        Session::flash('success', 'Upload successfully');

        return Redirect::route('projects.reportingDoc.create', $project->id)
            ->with('message', 'Files uploaded.');
    }
    else {
        return Redirect::route('projects.reportingDoc.create', $project->id)
            ->with('message', 'Something went wrong - Please try again.');
    }
    */
}

As you can see, I have commented out the file part for now. What I was going to do was get the paths for all the uploaded files, and serialize them into one field in the database - filePath.

However, to me this seems very messy. I would imagine it is best to have something like an uploads table which is linked to this model. I can then create an uploads object for each file that is uploaded.

One thing I am confused about is the form, and it being linked to my ReportingDoc Model. With this new approach, would I need to link it somehow to both models? ReportingDoc and Uploads?

Really, I am just looking for advice and guidance on the best way to achieve what I am after.

Many thanks

1 Answer 1

1
+100

You are already almost done. The best way to do what you're trying to achieve is to create a ReportingDocUpload model which belongs to ReportingDoc, then remove the filePath field from Reporting Doc.

Your model should look like: class ReportingDocUpload { ... protected $fillable = ['filepath', 'reportingdoc_id']; ... }

Then to save your files, do this:

if($file_count) {
    foreach($files as $file) {
        $destinationPath = public_path() .'/uploads/';
        $filename = $file->getClientOriginalName();
        $upload_success = $file->move($destinationPath, $filename);
        $rUpload = ReportingDocUpload::create(['filepath' => $filename, 'reportingdoc_id' => $reportingDoc->id]);
        $uploadcount ++;
    }
}

Don't forget to delete files from disk when the entry is deleted...

public static function boot()
{
    parent::boot();
    //delete associated file
    static::deleting(function($docUpload){
        try{
            $filepath = public_path('uploads/').$docUpload->filepath;
            if(file_exists($filepath))
            {
                unlink($filepath);
            }
        }
        catch(\Exception $e)
        {
            //some error while deleteing
            \Log::info('Error deleting: '.$filepath);
            \Log::debug($e);
        }
    });
}

Cheers..

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.