Laravel 6. Работа с изображениями при помощи Spatie Medialibrary

В этой статье я хочу рассказать как в небольшой проект на Laravel можно быстро добавить удобный инструмент для работы с изображениями - Spatie Media Library. Этот пакет хорошо известен и содержит подробную документацию. Коротко про преимущества, medialibrary позволяет:

  1. Связать изображение или группу изображений с вашей моделью в проекте. 
  2. Настроить преобразование изображений, размещая иx по коллекциям. 
  3. Производить манипуляции с изображениями, такими как сжатие и конвертация в другие форматы.
  4. Настраивать пользовательскую структуру каталогов.

В статье будет пошагово описано как можно использовать medialibrary в небольшом проекте. Проект будет иметь только одну модель Post, и будет добавлен простенький CRUD для полноценной демонстрации работы. Если вы планируете использовать уже существующую модель, пропустите шаги 1 - 6.

Шаг 1. Создание тестового приложения.

composer create-project --prefer-dist laravel/laravel test.loc

Шаг 2. Настройка соединения с базой данных

Дальше следует создать базу данных и в файле .env  настроить соединение .

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=lara-test
DB_USERNAME=root
DB_PASSWORD=

Шаг 3. Создание модели Post

В нашем тестовом проекте будет только одна модель Post, чтобы сгенерировать модель вместе с файлом миграции и контроллером ресурсов, используем команду.

php artisan make:model Post -mr

Эта команда создаст файлы модели Product.php, контроллер ProductController.php и файл миграции в папке database/migrations/   *.create_product_table.php

Шаг 4. Редактирование файла миграции

В файл миграции  добавим два поля  title и content, для заголовка и содержимого статьи

Schema::create('posts', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->string('title');
    $table->text('content');
    $table->timestamps();
});

Шаг 5. Создание маршрутов для модели Post

Далее необходимо подготовить маршруты для создание views c формой добавления постов. Так как контроллер у нас готов и содержит все необходимые методы, мы можем зарегистрировать маршрут:

Route::resource('/post', 'PostController');

Шаг 6. Создание CRUD и VIEWS

Хоть проект и тестовый, но для полноценной демонстрации возможностей пакета medialibrary придется создать простенький CRUD. Особо не заостряя внимания на стилях, создам несколько максимально упрощенных видов. Код проекта можно посмотреть на github.

В папке resources/views создаём папку posts и файлы для создания views

create.blade.php - страница создания поста
edit.blade.php   - страница редактирования поста
index.blade.php  - страница с выводом списка постов

Расположение файлов должно соответствовать изображению ниже:

post

Я собрал небольшую html страничку, подключил bottstrap cdn и добавил формы. Полный листинг можно посмотреть на  github. В результате должна получиться форма показанная на рисунке ниже:

p3
p2
 

Шаг 7. Установка и настройка medialibrary

Чтобы установить пакет medialibrary в вашем приложении  выполните в консоле следующую команду.

composer require "spatie/laravel-medialibrary:^7.0.0"

Дождитесь пока пакет будет скачан.

ready

Осталось только опубликовать и запустить миграцию:

php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider" --tag="migrations"
php artisan migrate

 migrate

После выполнения команды - миграции, будет создана новая таблица в базе данных с именем media, которая использует полиморфные отношения для хранения данных.

Шаг 8. Подготовка модели для работы с Media Library

Для связи нашей модели с medialibrary нужно в файл app\Post.php добавить связи c пакетом, имплементировать интерфейс и добавить трейт. В результате должно получиться так :

namespace App;

use Illuminate\Database\Eloquent\Model;
// use Media Library
use Spatie\MediaLibrary\HasMedia\HasMedia;
use Spatie\MediaLibrary\HasMedia\HasMediaTrait;

class Post extends Model  implements HasMedia
{
    use HasMediaTrait;

    protected $fillable = ['title','content'];

}

Зеленым подсвечены строки, который необходимо добавить к модели. Массив $fillable понадобиться для тестирования CRUD ниже.

Шаг 9. Связывание файлов с моделью

Для связывания изображений с моделью нужно внести изменения в PostController. В пункте 6 была создана форма с добавлением поста, следовательно нужно в контроллер добавить обработчик.

public function store(Request $request)
{
    $post = new Post($request->except(['image']));
    $post->save();

    if($request->hasFile('image') && $request->file('image')->isValid())
    {
       $post->addMediaFromRequest('image')->toMediaCollection('images');
    }

    return redirect()->route('posts.index');
}

В функции store() отработает сохранение данных и будет произведена  проверка на наличие у записи прикреплённого  медиафайла из коллекции "images", если нет, то в таблицу "media" будет сделана запись.

Существуют несколько методов API для добавления медиафайлов в зависимости от потребностей проекта:

addMediaFromRequest('image') - метод выбирает из текущего запроса изображение и добавляет в коллекцию images

addMediaFromRequest('image') - метод выбирает из текущего запроса нескольких файлов и добавляет их в коллекцию

addMediaFromUrl(string $url) - метод позволяет загрузить изображение из стороннего источника

Шаг 10. Изменение размеров изображений

Пакет medialibrary содержит прекрасный инструмент conversion для создания коллекций миниатюр разного формата. Для того, что бы его использовать, нужно в модель Post добавить функцию преобразования изображений. Для примера  добавим две коллекции для миниатюр thumb и для адаптивного вывода изображения full-size  .

public function registerMediaConversions(Media $media = null)
    {
        $this->addMediaConversion('thumb')
            ->width(100)
            ->height(100)
            ->sharpen(10);

        $this->addMediaConversion('full-size')
            ->greyscale()
            ->withResponsiveImages();
    }

После чего подключить связь моделью Media

use Spatie\MediaLibrary\Models\Media;

Теперь при загрузке изображения будет создана группа файлов со следующей иерархией:

listing

Шаг 11. Вывод изображения

Путь к изображению можно получить, обратившись к определённой коллекции, в нашем случае коллекция называется "images" :

<img src="{{$post->getFirstMediaUrl('images')}}" />  - путь к изображению с оригинальными размерами 
<img src="{{$post->getFirstMediaUrl('images', 'thumb')}}" /> - путь к изображению 100*100px
<img src="{{$post->getFirstMediaUrl('images', 'full-size')}}" /> - путь адаптивному изображению.

Если указать путь во views, изображение не отобразиться потому, что по умолчанию Laravel хранит все файлы в защищённом хранилище storage/app/public, и что бы сделать их публичными, нужно создать символьную ссылку на хранилище командой:

php artisan storage:link

Заключительная часть. Тестирование и выводы.

В итоге был развернут проект создана модель Post и подключен пакет Spatie Media Library. Осталось протестировать.

Сначала добавим новый пост, для этого нужно заполнить форму по пути /posts/create.

add postresult

 

На рисунках выше показан результат. Создание материала прошло успешно. В базе данных были созданы две записи:

В таблице post

post

В таблице media

media post

Как видно из записей, изображения привязаны через полиморфную связь, что очень удобно: нет нужды добавлять дополнительные поля к модели Post. Большим плюсом будет генерация коллекций изображений, где при конвертировании можно оптимизировать, изменить размер и даже изменить цветность.

 Если у вас остались вопросы, код проекта можно посмотреть на github.

Павел 30 марта, 2020

Не могу разобраться.
Почему-то $post->getFirstMediaUrl('images') дает путь с именем хоста, т.е. http://localhost/storage/6/image.jpg
Пересмотрел всю документацию, ответа не нашел. Может быть подскажите, где искать?
Спасибо

Павел 30 марта, 2020

Разобрался с проблемой- неправильно был установлен APP_URL в .env файле

Оставить комментарий

Похожие материалы