Мини-блог на Laravel, часть 4. Создание нового поста, загрузка и обрезка изображения
14.09.2020
Теги: Laravel • MySQL • PHP • route • Web-разработка • БазаДанных • Блог • Изображение • Класс • Практика • Форма • Фреймворк • ШаблонСайта
Теперь нам нужно реализовать остальные методы контроллера PostController — create()
, store()
, show()
, edit()
, update()
и destroy()
. Давайте создадим шаблон create.blade.php
, добавим два маршрута в файле routes/web.php
и внесем изменения в метод create()
, который будет просто показывать форму.
Шаблон, маршруты, метод контроллера
Новый шаблон
@extends('layouts.site') @section('content') <h1 class="mt-2 mb-3">Создать пост</h1> <form method="post" action="{{ route('post.store') }}"> @csrf <div class="form-group"> <input type="text" class="form-control" name="title" placeholder="Заголовок" required> </div> <div class="form-group"> <textarea class="form-control" name="excerpt" placeholder="Анонс поста" required></textarea> </div> <div class="form-group"> <textarea class="form-control" name="body" placeholder="Текст поста" rows="7" required></textarea> </div> <div class="form-group"> <input type="file" class="form-control-file" name="image"> </div> <div class="form-group"> <button type="submit" class="btn btn-primary">Сохранить</button> </div> </form> @endsection
Новые маршруты
<?php use Illuminate\Support\Facades\Route; Route::get('/', 'PostController@index')->name('blog.index'); Route::get('post/index', 'PostController@index')->name('post.index'); Route::get('post/search', 'PostController@search')->name('post.search'); Route::get('post/create', 'PostController@create')->name('post.create'); Route::post('post/store', 'PostController@store')->name('post.store');
Метод create()
class PostController extends Controller { /* ... */ public function create() { return view('posts.create'); } /* ... */ }
Ссылка на страницу с формой создания поста в layout-шаблоне:
<div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav mr-auto"> <li class="nav-item"> <a class="nav-link" href="#">Авторы</a> </li> <li class="nav-item"> <a class="nav-link" href="{{ route('post.create') }}">Создать</a> </li> <li class="nav-item"> <a class="nav-link" href="#">Контакты</a> </li> </ul> <form class="form-inline my-2 my-lg-0" action="{{ route('post.search') }}"> <input class="form-control mr-sm-2" type="search" name="search" placeholder="Найти пост..." aria-label="Поиск"> <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Поиск</button> </form> </div>
Подготовка файлового хранилища
Сразу после установки Laravel доступны диски local
и public
, использующие драйвер local
. Для диска local
место хранения — директория storage/app
, для диска public
место хранения — директория storage/app/public
. Диск local
является диском по умолчанию.
Чтобы сделать файлы диска public
доступными через веб, надо создать символьную ссылку из public/storage
на storage/app/public
. Директория public
проекта Laravel — является корневой директорией сервера, поэтому файл storage/app/public/image.jpg
будет доступен через веб как http://server.com/storage/image.jpg
.
> cd D:/work/localhost25/www > php artisan storage:link The [D:/work/localhost25/www/public/storage] link has been connected to [D:/work/localhost25/www/storage/app/public]. The links have been created.
Метод store() контроллера
Теперь можно приступать к реализации метода store()
контроллера PostController
:
<?php namespace App\Http\Controllers; use App\Post; use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage; class PostController extends Controller { /* ... */ public function store(Request $request) { $post = new Post(); $post->author_id = rand(1, 4); $post->title = $request->input('title'); $post->excerpt = $request->input('excerpt'); $post->body = $request->input('body'); $image = $request->file('image'); if ($image) { $path = Storage::putFile('public', $image); $post->image = Storage::url($path); } $post->save(); return redirect()->route('post.index'); } /* ... */ }
Сохраним в сессию сообщение, чем завершилось добавление поста:
class PostController extends Controller { /* ... */ public function store(Request $request) { /* ... */ return redirect()->route('post.index')->with('success', 'Новый пост успешно создан'); } /* ... */ }
И будем показывать это сообщение в layout-шаблоне:
<!doctype html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Веб-разработка</title> <link rel="stylesheet" href="{{ asset('css/app.css') }}"> <script src="{{ asset('js/app.js') }}"></script> </head> <body> <div class="container"> <nav class="navbar navbar-expand-lg navbar-dark bg-dark"> <!-- ... --> </nav> @if ($message = Session::get('success')) <div class="alert alert-success alert-dismissible mt-4" role="alert"> <button type="button" class="close" data-dismiss="alert" aria-label="Закрыть"> <span aria-hidden="true">×</span> </button> {{ $message }} </div> @endif @yield('content') </div> </body> </html>
Заодно подключим js-файл app.js
— без него сообщения работать не будут.
Создание превьюшки
Не слишком удачно, что в списке постов блога мы показываем большое изображение. Поэтому при добавлении нового поста будем создавать два уменьшенных изображения и сохранять путь к ним в базе данных. Для этого установим пакет intervention/image
с помощью composer
.
> cd D:/work/localhost25/www > composer require intervention/image
Открываем файл config/app.php
и добавляем следующие строки:
return [ /* ... */ 'providers' => [ /* ... */ Intervention\Image\ImageServiceProvider::class, ], 'aliases' => [ /* ... */ 'Image' => Intervention\Image\Facades\Image::class, ] /* ... */ ]
Исходный файл изображения будем сохранять без изменений в директорию storage/public/image/source
, а уменьшенные копии — в директории storage/public/image/image
и storage/public/image/thumb
. Так что эти три директории нужно сразу создать. Кроме того, добавить в таблицу БД posts
еще одно поле thumb
.
class PostController extends Controller { /* ... */ public function store(Request $request) { $post = new Post(); $post->author_id = rand(1, 4); $post->title = $request->input('title'); $post->excerpt = $request->input('excerpt'); $post->body = $request->input('body'); $source = $request->file('image'); if ($source) { $ext = str_replace('jpeg', 'jpg', $source->extension()); // уникальное имя файла, под которым сохраним его в storage/image/source $name = md5(uniqid()); Storage::putFileAs('public/image/source', $source, $name. '.' . $ext); // создаем jpg изображение для с страницы поста размером 1200x400, качество 100% $image = Image::make($source) ->resizeCanvas(1200, 400, 'center', false, 'dddddd') ->encode('jpg', 100); // сохраняем это изображение под именем $name.jpg в директории public/image/image Storage::put('public/image/image/' . $name . '.jpg', $image); $image->destroy(); $post->image = Storage::url('public/image/image/' . $name . '.jpg'); // создаем jpg изображение для списка постов блога размером 600x200, качество 100% $thumb = Image::make($source) ->resizeCanvas(600, 200, 'center', false, 'dddddd') ->encode('jpg', 100); // сохраняем это изображение под именем $name.jpg в директории public/image/thumb Storage::put('public/image/thumb/' . $name . '.jpg', $thumb); $thumb->destroy(); $post->thumb = Storage::url('public/image/thumb/' . $name . '.jpg'); } $post->save(); return redirect()->route('post.index')->with('success', 'Новый пост успешно создан'); } /* ... */ }
Все готово, осталось только изменить шаблоны index.blade.php
и search.blade.php
:
<img src="{{ $post->thumb ?? asset('img/default.jpg') }}" alt="" class="img-fluid">
Дополнительно
- Мини-блог на Laravel, часть 3. Постраничная навигация, layout-шаблон и поиск по блогу
- Блог на Laravel 7, часть 13. Загрузка и ресайз изображений для категорий и постов блога
- Блог на Laravel 7, часть 9. Панель управления — создание, публикация, удаление комментариев
- Блог на Laravel 7, часть 8. Панель управления — CRUD для категорий, тегов и пользователей
- Блог на Laravel 7, часть 7. Панель управления — создание, публикация, удаление постов
- Мини-блог на Laravel, часть 6. Исправление ошибок, удаление поста, семь маршрутов
- Мини-блог на Laravel, часть 5. Просмотр и редактирование отдельного поста блога
Поиск: Laravel • MySQL • PHP • Web-разработка • База данных • Блог • Класс • Форма • Фреймворк • Шаблон сайта • Практика • resize • image • Изображение • route • Маршрут