This is my image upload method of PostsController
public function store(Request $request, User $user, Image $image)
{
$this->validate($request, [
'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
'body' => 'required'
]);
if( $request->hasFile('image') ) {
$image = $request->file('image');
$filename = time() . '.' . $image->getClientOriginalExtension();
Image::make($image)->save( public_path('uploads/images/' . $filename ) );
}
$image = $filename;
auth()->user()->publish(
new Post(['body' => request('body'), 'image' => $image, 'user_id' => auth()->id()])
);
return redirect('/');
}
I want one method to upload image, video and audio as well with one input that user can upload image or video or audio
How can i do all these things in one controller?
First determine the whether the file is a video, audio or image. Then decide how you validate. Hope this will help.
if( $request->hasFile('file') ) {
$file = $request->file('file');
$imagemimes = ['image/png']; //Add more mimes that you want to support
$videomimes = ['video/mp4']; //Add more mimes that you want to support
$audiomimes = ['audio/mpeg']; //Add more mimes that you want to support
if(in_array($file->getMimeType() ,$imagemimes)) {
$filevalidate = 'required|mimes:jpeg|max:2048';
}
//Validate video
if (in_array($file->getMimeType() ,$videomimes)) {
$filevalidate = 'required|mimes:mp4';
}
//validate audio
if (in_array($file->getMimeType() ,$audiomimes)) {
$filevalidate = 'required|mimes:mpeng';
}
}
$this->validate($request, [
'file' => $filevalidate,
'body' => 'required'
]);
If you are using form requests, try with below code
public function rules() {
$rules = [
'some_field' => 'required',
];
// if fileType is audio
if ($this->input('fileType') == 'audio') {
$rules['file'] = 'mimes:mp3,mp4';
}
//if fileType is video
if ($this->input('fileType') == 'video') {
$rules['file'] = 'mimes:mp4,3gp';
}
return $rules;
}
field names and validation rules change as per your requirement.
Related
I am working on Laravel API project
I have destinations table and destination_images table with one-to-many relationship
When storing destination I am also receiving the images and store each image in Storage::disk('public') and generate random name for it and store the image name in the destination_images table
the store function
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required|string|max:100',
'description' => 'nullable|string',
'fileSource' => 'required'
]);
if ($validator->fails()) {
$errors = $validator->errors();
return response()->json($errors);
}
$destination = Destination::create([
'name' => $request->name,
'description' => $request->description
]);
foreach ($request->fileSource as $img) {
$extension = explode('/', explode(':', substr($img, 0, strpos($img, ';')))[1])[1];
$replace = substr($img, 0, strpos($img, ',')+1);
$image = str_replace($replace, '', $img);
$image = str_replace(' ', '+', $image);
$imageName = 'destination-' . Str::random(10).'.'.$extension;
Storage::disk('public')->put($imageName, base64_decode($image));
DestinationImage::create([
'destination_id' => $destination->id,
'img' => $imageName
]);
}
return response()->json('Destination Created Successfully');
}
My question is how to handle the show function? Should I use the image name I am getting from the database with a link in the frontend? What is the best practice for this process?
Laravel can automatically include your relationships. So when you show the Destination just include it. Notice i'm using model binding for the Destination.
public function show(Destianation $destination) {
$destination->load('destinationImage'); // load the relationship.
return $destination;
}
class DestinationImage {
protected $appends = [
'path',
];
public function getPathAttribute()
{
return Storage::disk('public')->path($this->img);
}
}
Now your response should look like this.
{
... // fields
destinationImages: [{
img: "somename.jpg",
}];
}
This is not enough to show the image, Laravel storage has a method called path, to get the full path of the image. Now you need to make an Eloquent Getter and append it to the DestinationImage model. This will automatically add it to your response.
class DestinationImage {
protected $appends = [
'path',
];
public function getPathAttribute()
{
return Storage::disk('public')->url($this->img);
}
}
I am working with Angular and Laravel on a project where I have destinations table
And I need to store destinations, and for every destination there is multiple images I need to store
So there is destination_images table, I made one-to-many relationship between the tables
So I have two models: Destination - DestinationImage
The store Laravel function
public function store(Request $request) {
$validator = Validator::make($request->all(), [
'name' => 'required|string|max:100',
'description' => 'required'
]);
if ($validator->fails()) {
$errors = $validator->errors();
return response()->json($errors);
}
$destination = Destination::create([
'name' => $request->name,
'description' => $request->description
]);
foreach ($request->fileSource as $img_code) {
$ext = explode('/', mime_content_type($img_code))[1];
$img_name = uniqid() . ".$ext";
$decoded_img = base64_decode($img_code);
$path = Storage::put('uploads/destinations' . $img_name, $decoded_img);
DestinationImage::create([
'destination_id' => $destination->id,
'img' => $img_name
]);
}
return response()->json('Destination Added Successfully');
}
and it stores the file successfully but now I need to retrieve the images from Laravel storage and show it in Angular so I made this function
public function view($id) {
$destination = Destination::findOrFail($id);
$destination_images = $destination->destination_images;
foreach ($destination_images as $destination_image) {
$url = Storage::url($destination_image->img);
return response()->json($url);
}
}
but the response is not completed url it's just "/storage/62a7056a5d8c6.png"
Please anyone can help me how to maintain the view function to show the images in Angular?
You are using storage path mean while client can't access to it.
First you need to enable storage link php artisan storage:link and it should able to access http://yourdomain.com/storage/62a7056a5d8c6.png
$image = App\Models\DestinationImage::find(1);
echo url("/destination_images/{$image->id}");
use Illuminate\Support\Facades\Storage;
public function view($id) {
$destination = Destination::findOrFail($id);
$destination_images = $destination->destination_images;
$imageList = [];
foreach ($destination_images as $destination_image) {
$imageList[] = Storage::url($destination_image->img);
return response()->json($imageList);
}
}
Validation of text and photo takes place in StorePost FormRequest.
public function rules()
{
return [
'name' => 'required',
'exerpt => 'required',
'photo' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
];
}
Then the controller part:
public function store( StorePost $request )
{
$imageName = time().'.'.$request->photo->extension();
$request->photo->move(public_path('post-images'), $imageName);
// may modify image name here but it's not elegant
//$data = $request->all();
//$data['photo'] = $imageName;
Post::create( $request->all() );
}
Image saves in MySQL as /private/var/folders/zr/y1drl_rs0sl75rxvgkx8ntzm0000gn/T/phpUJKeEG.
How can I set its name before the request gets to the controller?
I wouldn't like to do this such as here (commented lines).
You may use
$imageName = time().'_'.$request->photo->extension();
$request->photo->storeAs('public/post-images',$imageName);
$post = new Post;
//...
$post->photo = $imageName;
//...
$post->save();
Trying to implement update article in my update controller it seems works, but the problem is when I only want to update the post without uploading an image the old always getting remove which is it shouldn't.
here's my store function
public function store(Post $post)
{
$post->update($this->validateRequest());
$this->storeImage($post);
return redirect('post/'.$post->id)->with('success', 'New ariticle has been posted');
}
}
here's my validation
private function validateRequest()
{
return request()->validate([
'title'=> 'required',
'content' => 'required',
'image' => 'sometimes|image|max:5000',
]);
}
here's my update function
public function update(Post $post)
{
File::delete(public_path('storage/'.$post->image));
$post->update($this->validateRequest());
$this->storeImage($post);
return redirect('post/'.$post->id)->with('success', 'This post has
been Edited');
}
}
I've tried to add File::delete to my storeImage function and delete it from my update function, it fix the problem but the old image is not removed from directory
private function storeImage($post)
{
if (request()->has('image')){
File::delete(public_path('storage/'.$post->image))
$post->update([
'image' => request()->image->store('uploads', 'public'),
]);
$image = Image::make(public_path('storage/'.$post->image))->fit(750, 300);
$image->save();
}
}
Ok since I use model binding in my controller I don't have to find the id right?
so I change my update function which is basically Akhtar munir suggested, and turn out to be something like this. The image update work, it also remove the old image when I update it. But I have found another issue, the problem is when I edit article and title it didn't change like when I update it, I hope you can take look at this is this correct?
public function update(Post $post){
$this->validateRequest();
if(request()->hasFile('image') && request('image') != ''){
$imagePath = public_path('storage/'.$post->image);
if(File::exists($imagePath)){
unlink($imagePath);
}
$image = request()->file('image')->store('uploads', 'public');
$post->update([
'title' => request()->title,
'content' => request()->content,
'image' => $image,
]);
}
}
This is what I have done in one of my method. It may help you.
public function update(Request $request, $id)
{
if (UserDocument::where('id',$id)->exists()) {
$this->validateUserDocument($request);
if ($request->hasFile('doc_file') && $request->doc_file != '') {
$doc = UserDocument::where('id',$id)->first();
// dd($doc);
$file_path = storage_path().'/app/'.$doc['doc_file'];
//You can also check existance of the file in storage.
if(Storage::exists($file_path)) {
unlink($file_path); //delete from storage
// Storage::delete($file_path); //Or you can do it as well
}
$file = $request->file('doc_file')->store('documents'); //new file path
$doc->update([
'title' => $request->title,
'doc_file' => $file //new file path updated
]);
session()->flash('success','Document updated successfully!');
return redirect()->route('userdocs');
}
session()->flash('error','Empty file can not be updated!');
return redirect()->back();
}
session()->flash('error','Record not found!');
return redirect()->back();
}
In this code, I just simply want to clearify to you that I have stored image path in database, first I have retrieved that path and with that path I have found image in my local storage, delete it first and then update it with the new one. But make sure to store image path in database in both cases ofcourse with insert and update.
So finally you can also optimize your code like this, it will do the same thing as you expect, whether image and all data or only title and content.
public function update(Post $post){
$this->validateRequest();
$data = [
'title' => request()->title,
'content' => request()->content
];
if (request()->hasFile('image') && request('image') != '') {
$imagePath = public_path('storage/'.$post->image);
if(File::exists($imagePath)){
unlink($imagePath);
}
$image = request()->file('image')->store('uploads', 'public');
$data['image'] = $image;
//$post->update($data);
}
$post->update($data);
}
Try this one
private function storeImage($post)
{
if (request()->hasFile('image')){
$image_path = "/storage/".'prev_img_name'; // prev image path
if(File::exists($image_path)) {
File::delete($image_path);
}
$post->update([
'image' => request()->image->store('uploads', 'public'),
]);
$image = Image::make(public_path('storage/'.$post->image))->fit(750, 300);
$image->save();
}
}
I can't upload a photo when update a profile even i can upload it when i create profile in first time. In Update section, i put validation in form request for photo update and create. It's
'foto' => 'sometimes|image|max:500|mimes:jpeg,jpg,bmp,png',
Eveything good when upload in create. But, when upload for updating, warning appears because validation. Such 'The PHOTO must be an image.' or 'The PHOTO must be a file of type: jpeg,jpg,bmp,png.'
This my code :
On Controller for update :
public function update(Siswa $siswa, SiswaRequest $request){
$input = $request->all();
if($request->hasFile('foto')) {
$exist = Storage::disk('foto')->exists($siswa->foto);
if(isset($siswa->foto) && $exist) {
$delete = Storage::disk('foto')->delete($siswa->foto);
}
$foto = $request->file('foto');
$ext = $foto->getClientOriginalExtension();
if ($request->file('foto')->isValid()) {
$foto_name = date('YmdHis').".$ext";
$upload_path = 'fotoupload';
$request->file('foto')->move($upload_path, $foto_name);
$input['foto'] = $foto_name;
}
}
$siswa->update($input);
$telepon = $siswa->telepon ?? new Telepon();
$telepon->nomor_telepon = $request->input('nomor_telepon');
$siswa->telepon()->save($telepon);
$siswa->hobi()->sync($request->get('hobi_siswa', []));
return redirect('siswa');
}
This my code for validation in request
public function rules()
{
if($this->method() == 'PATCH') {
$id_rules = 'required|numeric|digits:8|unique:siswa,id,' . $this->get('id');
$telepon_rules = 'sometimes|numeric|digits_between:10,15|unique:telepon,nomor_telepon,' . $this->get('id') . ',id_siswa';
}
else {
$id_rules = 'required|numeric|digits:8|unique:siswa,id';
$telepon_rules = 'sometimes|numeric|digits_between:10,15|unique:telepon,nomor_telepon';
}
return [
'id' => $id_rules,
'nama_siswa' => 'required|regex:/^[\pL\s]+$/u|max:30',
'tanggal_lahir' => 'required|date',
'jenis_kelamin' => 'required|in:L,P',
'nomor_telepon' => $telepon_rules,
'id_kelas' => 'required',
'foto' => 'sometimes|image|max:500|mimes:jpeg,jpg,bmp,png',
];
}
So, i can't update my photo at all. How is the way to fix it?
Add this to your form. Maybe this will fix it.
enctype="multipart/form-data" :
<form action="..." class="...." method="post" enctype="multipart/form-data">