Error uploading images in Laravel

0

I am doing a blog in Laravel, the posts have images and when creating a post an image is uploaded. If the post is created the image is uploaded perfectly but when the post is edited and another image is uploaded it does not go up and also the address in the database changes to something like this:

C: \ xampp \ tmp \ phpCC3D.tmp

I have attached the controller code of the posts:

<?php

namespace App\Http\Controllers\Admin;

use Illuminate\Http\Request;  
use App\Http\Requests\PostStoreRequest;
use App\Http\Requests\PostUpdateRequest;
use App\Http\Controllers\Controller;

use Illuminate\Support\Facades\Storage;


use App\Post;
use App\Category;
use App\Tag;

class PostController extends Controller
{

public function __construct()
{
    $this->middleware('auth');
}

/**
 * Display a listing of the resource.
 *
 * @return \Illuminate\Http\Response
 */
public function index()
{
    $posts = Post::orderBy('id', 'DESC')
    ->where('user_id', auth()->user()->id)
    ->paginate();


    return view('admin.posts.index', compact('posts'));
}

/**
 * Show the form for creating a new resource.
 *
 * @return \Illuminate\Http\Response
 */
public function create()
{
    $categories = Category::orderBy('name', 'ASC')->pluck('name', 'id');
    $tags       = Tag::orderBy('name', 'ASC')->get();

     return view('admin.posts.create', compact('categories', 'tags'));
}

/**
 * Store a newly created resource in storage.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return \Illuminate\Http\Response
 */
public function store(PostStoreRequest $request)
{
    //validacion
    $post = Post::create($request->all());

    //IMAGE
    if($request->file('file')){
        $path = Storage::disk('public')->put('image', $request->file('file'));

        $post->fill(['file' => asset($path)])->save();
    }

    //TAGS
    $post->tags()->sync($request->get('tags'));

    return redirect()->route('posts.edit', $post->id)
        ->with('info', 'Entrada creada con exito');
}

/**
 * Display the specified resource.
 *
 * @param  int  $id
 * @return \Illuminate\Http\Response
 */
public function show($id)
{
    $post = Post::find($id);
    $this->authorize('pass', $post);

    return view('admin.posts.show', compact('post'));
}

/**
 * Show the form for editing the specified resource.
 *
 * @param  int  $id
 * @return \Illuminate\Http\Response
 */
public function edit($id)
{
    $post       = Post::find($id);
    $this->authorize('pass', $post);

    $categories = Category::orderBy('name', 'ASC')->pluck('name', 'id');
    $tags       = Tag::orderBy('name', 'ASC')->get();

    return view('admin.posts.edit', compact('post', 'categories', 'tags'));
}

/**
 * Update the specified resource in storage.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  int  $id
 * @return \Illuminate\Http\Response
 */
public function update(PostUpdateRequest $request, $id)
{
    $post = Post::find($id);
    $this->authorize('pass', $post);
    $post->fill($request->all())->save();

    //IMAGE 
    if($request->file('image')){
        $path = Storage::disk('public')->put('image',  $request->file('image'));
        $post->fill(['file' => asset($path)])->save();
    }

    //TAGS
    $post->tags()->sync($request->get('tags'));

    return redirect()->route('posts.edit', $post->id)->with('info', 'Entrada actualizada con éxito');
}

/**
 * Remove the specified resource from storage.
 *
 * @param  int  $id
 * @return \Illuminate\Http\Response
 */
public function destroy($id)
{
    $post = Post::find($id);
    $this->authorize('pass', $post);
    $post->delete();

    return back()->with('info', 'Eliminado correctamente');
}
}

What I think I should change in the code is the update part, only I do not see how to add it to delete the previous image:

 public function update(PostUpdateRequest $request, $id)
 {
    $post = Post::find($id);
    $this->authorize('pass', $post);
    $post->fill($request->all())->save();

    //IMAGE 
    if($request->file('image')){
        $path = Storage::disk('public')->put('image',  $request->file('image'));
        $post->fill(['file' => asset($path)])->save();
    }

    //TAGS
    $post->tags()->sync($request->get('tags'));

    return redirect()->route('posts.edit', $post->id)->with('info', 'Entrada actualizada con éxito');
}

What should I change in the code to delete the existing image and upload the new one?

Edit1: I was able to solve it, the problem was here:

public function update(PostUpdateRequest $request, $id)
{
$post = Post::find($id);
$this->authorize('pass', $post);
$post->fill($request->all())->save();

//IMAGE 
if($request->file('image')){
    $path = Storage::disk('public')->put('image',  $request->file('image'));
    $post->fill(['file' => asset($path)])->save();
}

It really should be like this:

public function update(PostUpdateRequest $request, $id)
{
$post = Post::find($id);
$this->authorize('pass', $post);
$post->fill($request->all())->save();

//IMAGE 
if($request->file('file')){
    $path = Storage::disk('public')->put('image',  $request->file('file'));
    $post->fill(['file' => asset($path)])->save();
}
    
asked by Kinafune 16.02.2018 в 00:53
source

2 answers

1

I see that you use a lot of features that Laravel provides; but there are a few that could serve you much more for what you are doing, then I will try to explain them to you.

Filesystem

First of all, we must understand something, will you frequently keep images in the system? If so, it is convenient to use the Local Disk that Laravel provides, this is not by default and therefore we must modify the configurations file of the filesystem of Laravel.

Once this is done, every time we want to make changes to disk; either through Request or facade Storage , all these changes will be made on the public disk without having the need to specify which disk we want to select.

Everything that I have just commented is completely optional, it is up to you to use it or not, but it should be noted that the code examples that I will use will take into account these changes.

File storage using Request

I think this is one of the features I liked most about Laravel 5.3, the ability to use the same Request to save files gives incredible flexibility when saving files.

Store function

public function store(PostStoreRequest $request)
{
    // Crea la instancia del post.
    $post = Post::create($request->all());

    // Guarda la imagen en el disco público.
    if ($request->hasFile('file')) {
        $path = $request->file('file')->store('image');

        // Es importante guardar el path del archivo, más adelante
        // explicaré el por qué.
        $post->file = $path;
    }

    // Tags
    $post->tags()->sync($request->get('tags'));

    return redirect()->route('posts.edit', $post->id)
        ->with('info', 'Entrada creada con exito');
}

To save files using Request , we only have to make sure that there is a file to save and of course the proposed validations that you want to apply to that file, for this I see that you have used a FormRequest that is just a good way to validate data.

Update function

function update(PostUpdateRequest $request, $id)
{
    // Es necesario lanzar una excepción si no encontramos el modelo.
    $post = Post::findOrFail($id);
    $this->authorize('pass', $post);

    // No es necesario guardar en este punto, ya que aún nos quedan
    // operaciones por realizar en el modelo.
    $post->fill($request->all());

    // Lógica para eliminar y guardar la nueva imágen.
    if ($request->hasFile('image')) {
        // Se toma el path de la imagen anterior y se elimina, nota
        // que es necesario usar el path relativo al sistema de archivos
        // en vez de usar el path completo del servidor, para ello es necesario
        // guardar el archivo sin usar la función asset().
        Storage::delete($post->file);

        // Se guarda el nuevo archivo y se asigna a su respectivo modelo.
        $path = $request->file('image')->store('image');
        $post->file = $path;
    }

    // Una vez terminadas las operaciones podemos guardar.
    $post->save();

    // Tags
    $post->tags()->sync($request->get('tags'));

    return redirect()->route('posts.edit', $post->id)->with('info', 'Entrada actualizada con éxito');
}

Why is it not necessary to use the asset() function when saving or updating the model?

Laravel provides an incredible amount of features out of the box that we can take advantage of, one of my favorites are the Accessors and the added values.

The Accessors roughly are functions that are executed when obtaining properties of a model; For example, if we wanted a user's name to be in uppercase without modifying its integrity in the DB, a Accessor would be a very good option.

For more information I recommend you take a look at the Laravel documentation:

If we define a Accessor in the model Post , for example in the following way:

<?php

// Estos datos sólo existirán en la serialización, eso
// significa que no necesitaremos modificar la base de datos
// para agregar este campo, ya que el Accessor se encargará de
// asignarle un valor cada vez que usemos por ejemplo $post->file_url,
// Laravel automáticamente se encagará de llamar la función
// getFileUrlAttribute cada vez que intentemos acceder a la propiedad
// file_url, por ende estos datos nunca existirán en la bd, lo cual es muy conveniente.
protected $appends = ['file_url'];

// Nos arrojará la dirección completa del archivo relativo a la dirección del servidor.
public function getFileUrlAttribute() {
    return Storage::url($this->attributes['file']);
}

All the operations we perform using the file_url property will be executed by the function getFileUrlAttribute() , the reason why we separate the URL and the address of the file is because the file system always works relative to its disk address .

That is, if we try to delete a file using the address that throws the function asset() , example: www.tu-sitio-web.com/images/tu-imagen-en-disco.jpeg

The previous example would send us an error if we tried to use Storage::delete($path) , since we would wait as input: /images/ tu-imagen-en-disco.jpeg

Of course this can be solved with regular expressions or even using cycles, but I think it is more convenient and powerful to take advantage of the functions that Laravel brings us from the beginning.

If we try to use, for example $post->file , we would get /images/ tu-imagen-en-disco.jpeg and if we try to use $post->file_url we would obtain www.tu-sitio-web.com/images/tu-imagen-en-disco.jpeg which leaves us a very efficient way to use this data without having to make changes in the view or in JavaScript (if we use Laravel API), these values exist in JSON as in PHP , so there is no need to worry that they are not present in our transformations.

I recommend you check:

I hope I have solved your problem and clarify some doubts that may have arisen.

Greetings.

    
answered by 16.02.2018 / 18:58
source
0

I do the following, I hope it works for you:

if ($request->hasFile('image')) {
    $logoName = $this->updateLogo($request);
    $request->merge(['logo' => $logoName]);
}

$user->update($request->all());

You just need to write a condition to delete the image.

public function updateLogo($request)
{
    $file = $request->file('image');
    $name = $file->getClientOriginalName();

    if ($request->user()['logo'] != null) {
        \Storage::delete('images/logos/'.$request->user()['logo']);
    }

    $file->storeAs('images/logos', $name);
    return $name;
}
    
answered by 16.02.2018 в 15:01