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();
}
}
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);
}
}
I am trying to make store method where placing 2 different type of files - .pdf and .step.
First issue, that .pdf file is moved to wanted directory, but in database storing temporary location like C:\xampp\tmp\phpAA39.tmp etc...
At the start was same issue with .step files, but i tried to update my code and now it's not even storing path to database. Both files are placing to storage/models and storage/drawings how it should be, but .step files are saving as .txt by some reasons.
ProductController:
public function store(Order $order, Request $request){
$this->validate($request, [
'name'=>'required',
'drawing'=>'nullable|file',
'_3d_file'=>'nullable|file',
'quantity'=>'integer',
'unit_price'=>'required',
'discount'=>'nullable'
]);
if (request('drawing')) {
request('drawing')->store('drawings');
}
if (request('_3d_file')) {
request('_3d_file')->store('models');
}
// dd(request()->all());
$order->products()->create($request->all());
session()->flash('product-created', 'New product was added successfully');
return redirect()->route('order', $order);
}
Update:
Figured out, how to solve an extension and temp location stuff... but still don't understand why on my store method does not storing 3dfile path while with drawing is ok and code is exactly the same. Also on update method it stores path with no errors. Any thoughts?
public function store(Order $order){
$inputs = request()->validate([
'name'=>'required',
'drawing'=>'file',
'_3d_file'=>'file',
'quantity'=>'integer',
'unit_price'=>'required',
'discount'=>'nullable'
]);
if (request('drawing')) {
$filename = request('drawing')->getClientOriginalName();
$inputs['drawing'] = request('drawing')->storeAs('drawings', $filename);
}
if (request('_3d_file')) {
$filename = request('_3d_file')->getClientOriginalName();
$inputs['_3d_file'] = request('_3d_file')->storeAs('models', $filename);
}
//dd($inputs['_3d_file']);
$order->products()->create($inputs);
session()->flash('product-created', 'New product was added successfully');
return redirect()->route('order', $order);
}
update
public function update(Product $product){
$inputs = request()->validate([
'name'=>'required',
'drawing'=>'nullable|file',
'_3d_file'=>'nullable|file',
'quantity'=>'integer',
'unit_price'=>'required',
'discount'=>'nullable'
]);
if (request('drawing')) {
$filename = request('drawing')->getClientOriginalName();
$inputs['drawing'] = request('drawing')->storeAs('drawings', $filename);
$product->drawing = $inputs['drawing'];
}
if (request('_3d_file')) {
$filename = request('_3d_file')->getClientOriginalName();
$inputs['_3d_file'] = request('_3d_file')->storeAs('models', $filename);
$product->_3d_file = $inputs['_3d_file'];
}
$product->name = $inputs['name'];
$product->quantity = $inputs['quantity'];
$product->unit_price = $inputs['unit_price'];
$product->discount = $inputs['discount'];
$product->save();
session()->flash('product-updated', 'The product was updated successfully');
return redirect()->route('product', $product);
}
I am passing the post object to update my post but To my surprise when I try to edit a single post all my posts are been replaced with the edited values (image or text) that I entered when trying to edit.
Postcontroller
public function update(Post $id){
$data = request()->validate([
'about' => 'required',
'image' => '',
]);
if(request('image')){
$imagePath = request('image')->store('uploads','public');
$image = Image::make(public_path("storage/{$imagePath}"))->fit(500,500);
$image->save();
$imageArray = ['image' => $imagePath];
}
auth()->user()->posts()->update(array_merge( $data, $imageArray ?? [] ) );
$user = Auth::guard('web')->id() ;
return redirect()->route('home',['user'=>$user]);
}
route
Route::get('/post/edit/{post}', 'PostController#edit')->name('post.edit');
Route::patch('/p/update/{id}', 'PostController#update')->name('post.update');
your code will be updating all posts for this authenticated user.
in order to fix this issue :
Route::get('/post/edit/{post}', 'PostController#edit')->name('post.edit');
Route::patch('/post/edit/{post}', 'PostController#update')->name('post.update');
and in your controller
public function update(Post $post){
// validation code here
// image upload code
// update your database
$post->update([
//update database fields
]);
return redirect('home');
}
I'm using Yii2 basic. It doesn't seems like anything's wrong, no error message displayed, but why did my image didn't upload? The rest (title, content etc) get uploaded through the form,though
This is my model's rule and related method:
public $image;
public function init(){
Yii::$app->params['uploadPath'] = Yii::$app->basePath . '/uploads/batam/';
Yii::$app->params['uploadUrl'] = Yii::$app->urlManager->baseUrl . '/uploads/batam/';
}
public function rules()
{
return [
[['title', 'content'], 'required'],
[['content'], 'string'],
[['created_at', 'updated_at','image'], 'safe'],
[['image'], 'file','extensions'=>'jpg,png,jpeg'],
[['title'], 'string', 'max' => 255],
];
}
public function getImageFile()
{
return isset($this->image) ? Yii::$app->params['uploadPath'].$this->image : null;
}
public function uploadImage() {
$image = UploadedFile::getInstance($this, 'image');
if (empty($image)) {
return false;
}
$this->image = $image->name;
return $image;
}
This is my controller
public function actionCreate()
{
$model = new News();
if ($model->load(Yii::$app->request->post()) )
{
// process uploaded image file instance
$image = $model->uploadImage();
if($model->validate())
{
if($model->save())
{
// upload only if valid uploaded file instance found
if ($image !== false)
{
$path = $model->getImageFile();
$image->saveAs($path);
}
return $this->redirect(['view', 'id'=>$model->id]);
}
}
else{echo " validation is failed";}
}
else{
return $this->render('create', [
'model' => $model,
]);
}
}
This is the form
echo $form->field($model, 'image')->widget(FileInput::classname(), [
'options' => ['accept' => 'image/*'],
'pluginOptions' => [['previewFileType' => 'any']]
]);
I had included the enctype also at the beginning of the form
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]);
At this point inside the if ($image !== false) part of the controller , the $image and $path to be saved-as contains a seemingly correct path.
This is my $path : C:\xampp\htdocs\gbia/uploads/batam/test image 1-01.jpg and my $image also contain the object (not null). This is the var_dump of my $image :
object(yii\web\UploadedFile)#179 (5) { ["name"]=> string(19) "test image 1-01.jpg" ["tempName"]=> string(24) "C:\xampp\tmp\php3199.tmp" ["type"]=> string(10) "image/jpeg" ["size"]=> int(925184) ["error"]=> int(0) }
I think something wrong with the saveAs(), but I can't figure it out. Had googled around, look on stackoverflow and tutorials but I still can't find any answer. Can someone help? Thanks
Check your model, you have declared $image as a public variable of the class, and not as a field in the database, if you want to store the data there, it will never work, as the public property that is temporary will have preference over the database column.
public $image;
So delete this field (If it is also in the db) or generate a new column name (I suggest by the name of path).
[['content', 'path'], 'string'],
Then you need to store the path, I don't see where are you doing that in the controller or class. I suggest you to add a field in the database with the "path" name and then do like this in the controller:
$path = $model->getImageFile();
$image->saveAs($path);
$model->path = $path . $image // You must store the full path plus the file name
$model->save(); // then you save the model again
Any doubt is welcome, I have example projects that I can show you if you are unable to see the light.