将数据传递到Laravel 5中的FormRequest

In Laravel 5 how do you pass data into the FormRequest class?

Background

I am attempting to validate a get variable that comes from a HTML select element.

I am doing this by subclassing FormRequest and adding to the rules array. I would like to build this validation rule dynamically from the list of files to stay DRY.

What is the best way to pass this list into FileFormRequest?

app/Http/Controllers/UploadController.php (please excuse the public property)

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Requests\FileFormRequest;
use App\Http\Controllers\Controller;
use File;

class UploadController extends Controller
{

    public $files = [];

    public function get(FileFormRequest $request)
    {
        $files_dir = storage_path('app').'/spreadsheets';
        foreach (File::allFiles($files_dir) as $file) {
            $file = $file->getBasename();
            $this->files[$file] = $file;
        }

        return view('main', array(
            'title' => '',
            'file_names' => $this->files,
            'file_name' => '',
            'sheet_name' => '',
            'encoding' => 'UTF-8'
        ));
    }

}

app/Http/Requests/FileFormRequest.php

<?php namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Response;

class FileFormRequest extends FormRequest
{

    public function rules()
    {
        // What goes here in place of the empty array?
        $files = implode(',', []);

        return [
            'file_name' => 'sometimes|required|in:'.$files,
        ];

    }

    public function authorize()
    {
        return true;
    }
}

OK I solved this by

  • moving the upload file listing functionality into a utility interface and class
  • using a service provider to expose an instance of the utility class as a service
  • injecting the service into both the Controller and FormRequest classes

Code was:

app/Contracts/Utilities/UploadFilesContract.php - create the interface

<?php

namespace App\Contracts\Utilities;

interface UploadFilesContract {

    public function __construct($dir);

    public function getDir();

    public function getFilesBasenames();

}

app/Utilities/UploadFiles.php - create the class with the listing functionality

<?php

namespace App\Utilities;

use Illuminate\Support\Facades\File;
use App\Contracts\Utilities\UploadFilesContract;

class UploadFiles implements UploadFilesContract {

    private $dir;
    private $files;

    public function __construct($dir = '')
    {
        $this->dir = storage_path('app').(0 < strlen($dir) ?  '/'.$dir : '');
        $this->files = File::allFiles($this->dir);
    }

    public function getDir()
    {
        return $this->dir;
    }

    public function getFilesBasenames()
    {
        $files = [];
        foreach ($this->files as $file) {
            $file = $file->getBasename();
            $files[$file] = $file;
        }
        return $files;
    }

}

app/Providers/UploadFilesServiceProvider.php - bind the interface to an instance of the class

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Utilities\UploadFiles;

class UploadFilesServiceProvider extends ServiceProvider
{
    protected $defer = true;

    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->bindShared('App\Contracts\Utilities\UploadFilesContract', function($app) {
            return new UploadFiles('spreadsheets');
        });
    }

    public function provides()
    {
        return ['App\Utilities\UploadFiles'];
    }
}

app/Http/Controllers/UploadController.php - inject the uploaded files interface in the constructor

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Requests\FileFormRequest;
use App\Contracts\Utilities\UploadFilesContract;

class UploadController extends Controller
{

    private $upload_files;

    public function __construct(UploadFilesContract $upload_files) {
        $this->upload_files = $upload_files;
    }

    public function get(FileFormRequest $request)
    {   
        return view('main', array(
            'title' => '',
            'file_names' => $this->upload_files->getFilesBasenames(),
            'file_name' => '',
            'sheet_name' => '',
            'encoding' => 'UTF-8'
        ));
    }

}

app/Http/Requests/FileFormRequest.php - inject the uploaded files interface in the constructor

<?php namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use App\Contracts\Utilities\UploadFilesContract;

class FileFormRequest extends FormRequest
{
    private $upload_files;

    public function __construct(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null, UploadFilesContract $upload_files)
    {
        parent::__construct($query, $request, $attributes, $cookies, $files, $server, $content);
        $this->upload_files = $upload_files;
    }

    /**
     * @return array
     */
    public function rules()
    {
        $files = implode(',', $this->upload_files->getFilesBasenames());

        $rules = [
            'file_name' => 'sometimes|required|in:'.$files,
        ];

        return $rules;
    }

    /**
     * @return bool
     */
    public function authorize()
    {
        return true;
    }
}

config/app.php - register the provider

<?php

// ...

'providers' => [

    // ...

    App\Providers\UploadFilesServiceProvider::class,

],

// ...

You may try this:

public function rules()
{
    // Get the REQUEST (GET/POST) variable
    $files = app('request')->get('form_field_name');

    return [
        'file_name' => 'sometimes|required|in:'.$files,
    ];

}

If form_field_name is not an array then make it an array depending on the value it contains. Also, you may create another protected method to get input from request if that requires much code, for example:

protected function getRequestInput()
{
    $files = app('request')->get('form_field_name');

    // Process it here and finally return, i.e:
    return $files; // array
}

So you are now able to call the method from within rules method like this:

$files = $this->getRequestInput();