Why are you trying to validate after you process the request ?
Mission Impossible ? [Laravel 6 + InterventionImage + validation]
Hey everyone, this is my first post on Laracasts so bear with me :)
I'm trying to figure out how to safely validate a file (image) upload during the creation of a new model instance. I need to make use of the InterventionImage library, so that the image is manipulated (cropped) when the new model instance is created.
Here's my model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class TestProfile extends Model
{
protected $fillable = [
'name',
'main_picture',
];
}
And this is my controller:
namespace App\Http\Controllers;
use App\TestProfile;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\View\View;
use Intervention\Image\Facades\Image;
class TestProfileController extends Controller
{
/**
* Display a listing of the TestProfiles.
*
* @return View
*/
public function index()
{
$testprofiles = TestProfile::latest()->get();
return view('testprofiles.index', ['testprofiles' => $testprofiles]);
}
/**
* Display the specified TestProfile.
*
* @param TestProfile $testprofile
*
* @return View
*/
public function show(TestProfile $testprofile)
{
return view('testprofiles.show', compact('testprofile'));
}
/**
* Show the form for creating a new TestProfile.
*
* @return View
*/
public function create()
{
return view('testprofiles.create');
}
/**
* Store a newly created TestProfile in storage.
*
* @param Request $request
*
* @return Application|RedirectResponse|Redirector
*/
public function store(Request $request)
{
TestProfile::create( $this->validateTestProfile() );
return redirect( route('testprofiles.index') );
}
/**
* Show the form for editing the specified TestProfile.
*
* @param TestProfile $testprofile
*
* @return View
*/
public function edit(TestProfile $testprofile)
{
return view( 'testprofiles.edit', compact('testprofile') );
}
/**
* Update the specified TestProfile in storage.
*
* @param Request $request
* @param TestProfile $testprofile
*
* @return Application|RedirectResponse|Redirector
*/
public function update(Request $request, TestProfile $testprofile)
{
$testprofile->update( $this->validateTestProfile() );
return redirect( route('testprofiles.show', $testprofile) );
}
/**
* Remove the specified TestProfile from storage.
*
* @param TestProfile $testprofile
*
* @return Response
*/
public function destroy(TestProfile $testprofile)
{
//
}
/* ---------------------
UTILITIES
---------------------- */
/**
* Validates the input data. Useful for creating as well as updating a TestProfile.
*
* @return array
*/
protected function validateTestProfile() {
if( request()->hasFile('main_picture') ) {
$extension = request()->file('main_picture')->getClientOriginalExtension(); // get file extension
$filename_to_store = time() . '_' . Str::random(40) . '.' . $extension; // filename to store
// "Make" the resized image
$resized = Image::make( request()->file('main_picture') )
->resize(300, 300, function( $constraint ) {
$constraint->aspectRatio(); // preserve image's aspect ratio
});
$save_resized = $resized->save('uploads/testprofiles/main_picture/' . $filename_to_store);
$filename_resized = $save_resized->basename;
$request['main_picture'] = $filename_resized;
}
return request()->validate([
'name' => 'required',
'main_picture' => 'required|image|mimes:jpeg,jpg,png,gif|max:1024',
]);
}
}
With my current setup, I'm getting an Unsupported Image Type exception from InterventionImage if I chose anything else other than an image (for example a .PDF file). However, if I chose an actual image file, the store() method within the controller is successfully executed, and the TestProfile instance gets created. My understanding is, that the validation doesn't work.
The second problem that I'm having with this approach, is that the main_image field of the TestProfile model instance in the database gets saved as a temporary system path, for example /private/var/tmp/phpPGy8PH.
I've been trying to figure this one out for a couple days now, and it's getting really frustrating. If anyone could help me out, I'd highly appreciate it.
May i suggest to simplify it a bit ? Can you try something like that for example warning not tested
public function store(Request $request)
{
$request->validate([
'name' => 'required',
'main_picture' => 'required|image|mimes:jpeg,jpg,png,gif',
]);
$extension = request()->file('main_picture')->getClientOriginalExtension();
$filename_to_store = time() . '_' . Str::random(40) . '.' . $extension;
$resized = Image::make( request()->file('main_picture') )
->resize(300, 300, function( $constraint ) {
$constraint->aspectRatio();
})->stream();
Storage::disk('local')->put($filename_to_store, (string) $resized);
TestProfile::create([
'name' => $request->input('name'),
'main_picture' => $filename_to_store
]);
return redirect( route('testprofiles.index') );
}
Please or to participate in this conversation.