Работа с изображениями в Laravel, Image Intervention

В этом посте я попробую показать как использовать пакет для работы с изображениями Image Intervention в Laravel.

Обычно Image Intervention используют для загрузки и стандартной работы с изображениями (изменением размера, обрезкой и т.п.). Создадим для примера простое приложение для публикации новостей, которое будет иметь всего две функции:

  • вывод всех новостей;
  • добавить новость с картинкой.

Сразу создадим модель, миграцию и контроллер ресурсов для наших новостей, выполнив команду:

php artisan make:model News -mcr

Открываем созданный файл миграции /database/migrations/XXXX_XX_XX_XXXX_create_news_table.php и добавляем нужные поля, их буде три: название, содержание, картинка.

 public function up()
    {
        Schema::create('news', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->text('body');
            $table->string('image');
            $table->timestamps();
        });
    }

Выполняем миграцию php artisan migrate

Создаем Blade шаблон для главной страницы новостей resources/views/news/index.blade.php

Пока там будет заглушка, просто напишем слово «Новости».

Далее настроим роуты добавив в файл /routes/web.php

Route::resource('news', 'NewsController');

Теперь в контроллере app/Http/Controllers/NewsController.php в методе index() вызовем шаблон index.blade.php

public function index()
    {
        return view('news.index');
    }

Переходим по http://нашсайт/news и убеждаемся что все работает.

Далее создаем форму для добавления новостей resources/views/news/create.blade.php

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">

    <title>Добавление новости</title>
</head>
<body>

<div class="container">
    <div class="col-8">
        <h1>Добавить новость</h1>
        <form method="post" action="{{ route('news.store') }}" enctype="multipart/form-data">
            @csrf
            <div class="form-group">
                <label for="name">Название новости</label>
                <input type="text" class="form-control" id="name" name="name">
            </div>
            <div class="form-group">
                <label for="body">Содержание</label>
                <textarea class="form-control" id="body" rows="3" name="body"></textarea>
            </div>
            <div class="form-group">
                <label for="image">Картинка для новости</label>
                <input type="file" class="form-control-file" id="image" name="image">
            </div>
            <button type="submit" class="btn btn-primary">Добавить</button>
        </form>
    </div>
</div>
</body>
</html>

Изменим в нашем контроллере новостей метод create():

public function create()
    {
        return view('news.create');
    }

Теперь у нас по адресу http://нашсайт/news/create открывается форма добавления новости с картинкой, на этом подготовительный этап закончен.

Форма добавления новости с картинкой

Работа с Intervention Image в Laravel

Теперь добавим к нашему проекту пакет Intervention Image http://image.intervention.io/ с помощью Composer, идем в терминал и выполняем команду

composer require intervention/image

После установки открываем конфигурационный файл нашего приложения config/app.php и в массив providers добавляем сервис провайдер установленного пакета:

'providers' => [

	…….
        /*
         * Package Service Providers...
         */
        Intervention\Image\ImageServiceProvider::class,
	……
	
    ],

Так же добавляем фасад в массив aliases:

'aliases' => [

	…..
        'Image' => Intervention\Image\Facades\Image::class,

    ],

Далее в нашем контроллере новостей изменяем метод store():

  public function store(Request $request)
    {
        $data = $request->all();

        $filename    = $data['image']->getClientOriginalName();

        //Сохраняем оригинальную картинку
        $data['image']->move(Storage::path('/public/image/news/').'origin/',$filename);

        //Создаем миниатюру изображения и сохраняем ее
        $thumbnail = Image::make(Storage::path('/public/image/news/').'origin/'.$filename);
        $thumbnail->fit(300, 300);
        $thumbnail->save(Storage::path('/public/image/news/').'thumbnail/'.$filename);

        //Сохраняем новость в БД
        $data['image'] = $filename;
        News::create($data);

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

Не забываем в начало контроллера добавить:

use Illuminate\Support\Facades\Storage;
use Intervention\Image\Facades\Image;

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

Далее в модель новостей app/News.php добавить переменную $fillable с полями БД, которые мы будем записывать:

class News extends Model
{
    protected $fillable = ['name', 'body', 'image'];
}

Переходим http://нашсайт/news/create и пробуем добавить новость. В случае успешной добавлении новости, запись появляется в БД, добавляются 2 файла изображения (оригинал и миниатюра) и нас переадресовывает на главную страницу.

В случае если у вас возникла ошибка «Can’t write image data to path…» попробуйте вручную создать папку public/image/news/thumbnail

В завершении выведем на главной страницы новостей их название и миниатюры изображений, для этого в контроллере app/Http/Controllers/NewsController.php немного изменим метод index():

 public function index()
    {
        return view('news.index',['news' => News::all()]);
    }

И шаблон resources/views/news/index.blade.php

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">

    <title>Список новостей</title>
</head>
<body>

<div class="container">
    @foreach($news as $item)
        <div class="col-8">
            <h2>{{ $item->name }}</h2>
            p><img src="{{ Storage::url('image/news/thumbnail/'.$item->image) }}" alt=""></p>
        </div>
    @endforeach
</div>
</body>
</html>

Перейдем http://нашсайт/news/ и убедимся, что все работает.

Вывод списка новостей

Итак, мы разобрали как можно работать с изображениями с помощью пакета Intervention Image добавив его к своему проекту в Ларавел. Выше мы использовали только метод fit() из этого пакета, какие еще существуют методы можно прочитать на официальном сайте http://image.intervention.io/

Хостинг для ваших проектов