Статьи по Laravel

Как загрузить изображение через Ajax (используя Laravel в качестве бэкэнда)

Что мы будем делать

У пользователя есть фотография профиля по умолчанию.

Пользователь нажимает на фотографию своего профиля, и у него появляется возможность выбрать новую фотографию ( при этом он может нажать кнопку отмены, и ничего не произойдет).

Если пользователь выбирает изображение, то изображение его профиля обновляется сразу же (нет необходимости перезагружать страницу, изменения сохраняются).

Как мы будем это делать

У нас есть много способов это реализовать.

В данном случае мы сделаем это следующим образом:

  • Мы добавим форму (но с помощью стилей сделаем так, чтобы она оставалась скрытой). Эта форма будет содержать поле типа file
  • С помощью Javascript мы привяжем событие клика к изображению профиля. Когда это событие будет идентифицировано, мы запустим click на вводе файла.
  • Мы будем слушать событие изменения входных данных, так что когда файл будет выбран, мы сделаем AJAX-запрос для изменения изображения профиля.
  • AJAX-запрос вернет сообщение об успехе или неудаче. Если ответ был успешным, то мы обновим изображение профиля с помощью Javascript (чтобы не обновлять страницу).

Погнали

Форма будет скрыта с помощью свойства CSS под названием display (со значением none).

В данном случае я размещаю ее непосредственно перед изображением.

<form action="{{ url('profile/foto') }}" method="post" style="display: none" id="avatarForm"> {{ csrf_field() }} <input type="file" id="avatarInput" name="photo"> </form> <img src="{{ auth()->user()->getAvatarUrl() }}" id="avatarImage">
Code language: HTML, XML (xml)

Обратите внимание:

  • Форма, а также изображение и ввод, имеют свой id (это важно для доступа к этим элементам через Javascript).
  • Входной тип файла имеет атрибут name со значением photo (это значение должно соответствовать тому, которое указано в нашем контроллере, чтобы правильно получить загруженный файл из бэкенда).
  • Я упростил код, удалив атрибуты class, alt и title из моего изображения (вы можете использовать эти атрибуты по своему усмотрению в своих проектах).

Что на счет Javascript?

Как я уже говорил, нам нужно зарегистрировать 2 события. А также получить данные об элементах.

$(function () { var $avatarImage, $avatarInput, $avatarForm; $avatarImage = $('#avatarImage'); $avatarInput = $('#avatarInput'); $avatarForm = $('#avatarForm'); $avatarImage.on('click', function () { $avatarInput.click(); }); $avatarInput.on('change', function () { alert('change'); }); });
Code language: PHP (php)

Как вы могли заметить, в событии изменения input я поместил только одно оповещение.

На этом этапе вы должны убедиться, что получили это сообщение, после нажатия на изображение и выбора файла.

Если все в порядке, то вы можете заменить оповещение для выполнения Ajax-запроса.

Таким образом, мы получим следующее:

$avatarInput.on('change', function () { var formData = new FormData(); formData.append('photo', $avatarInput[0].files[0]); $.ajax({ url: $avatarForm.attr('action') + '?' + $avatarForm.serialize(), method: $avatarForm.attr('method'), data: formData, processData: false, contentType: false }).done(function (data) { if (data.success) $avatarImage.attr('src', data.path); }).fail(function () { alert('Неправильный формат изображения.'); }); });
Code language: PHP (php)

Здесь мы должны помнить, что:

  • Мы получаем url, к которому будет сделан запрос, и method из значений, определенных в форме.
  • Мы используем объект FormData для загрузки изображения через Ajax (поскольку метод serialize в данном случае передает только токен csrf).
  • Ответ, который мы получаем от Ajax-запроса, состоит из объекта, который мы называем data и который имеет 2 атрибута (success, чтобы указать, была ли операция успешной, и path с путем к изображению профиля).

Нам нужно зарегистрировать только путь profile/photo (который мы использовали в action формы). При желании вы можете использовать другой путь.

Этот маршрут должен быть объявлен в файле Laravel routes.

Route::post('/profile/foto', 'ProfileController@updatePhoto');
Code language: PHP (php)

В этом случае маршрут определяется через контроллер под названием ProfileController. В частности, через метод updatePhoto.

Таким образом, в этом контроллере у нас будет следующее:

public function updatePhoto(Request $request) { $this->validate($request, [ 'photo' => 'required|image' ]); $file = $request->file('photo'); $extension = $file->getClientOriginalExtension(); $fileName = auth()->id() . '.' . $extension; $path = public_path('images/users/'.$fileName); Image::make($file)->fit(144, 144)->save($path); $user = auth()->user(); $user->photo_extension = $extension; $saved = $user->save(); $data['success'] = $saved; $data['path'] = $user->getAvatarUrl() . '?' . uniqid(); return $data; }
Code language: PHP (php)

Данный метод:

  • Проверяет, что поле photo, отправленное в запросе, является изображением (а также является обязательным полем).
  • Получает название изображения. Таким образом идентификатор пользователя, после которого следует расширение, будет именем файла для сохранения.
  • Он использует интерфейс Image facade, поэтому если изображение больше 144×144 пикселей, то его размер изменяется в соответствии с этим ограничением.
  • Хранит в таблице пользователей в столбце photo_extension имя загруженного изображения.
  • Возвращает ответ в формате JSON, указывающий, была ли операция успешной, а также отправляет обратно URL изображения.

Чтобы приведенный выше код работал правильно, необходимо, чтобы в таблице пользователей был столбец photo_extension.

$table->string('photo_extension')->nullable();
Code language: PHP (php)

Вам также необходимо определить метод getAvatarUrl в модели User.

public function getAvatarUrl() { if ($this->photo_extension) return asset('images/users/'.$this->id.'.'.$this->photo_extension); return asset('images/users/default.jpg'); }
Code language: PHP (php)

Этот метод возвращает абсолютный URL-адрес изображения профиля пользователя. А в случае, если его нет, абсолютный URL-адрес изображения по умолчанию.

Если вы еще не установили пакет Intervention/Image (необходимый для работы изменения размера изображения), вы можете установить его, просто выполнив команду:

composer require intervention/image
Code language: JavaScript (javascript)

Кстати. Если вы достаточно внимательны, то могли заметить использование uniqid() в методе updatePhoto. Этот метод используется для добавления уникального номера в конец имени файла, чтобы пользователь всегда видел свою новую фотографию профиля (поскольку ранее он мог загрузить изображение с тем же названием, которое сохранилось в кэше браузера).

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *