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,
],
// ...