Если видео недоступно для просмотра, попробуйте выключить блокировщик рекламы.

Создание сущности в CRUD требует наличия двух маршрутов: один для отображения формы, другой для обработки формы. Кроме того, важно понимать как взаимодействуют между собой эти маршруты, как обрабатываются ошибки и так далее. Начнем с того что у нас есть три состояния:

  • Отображение новой формы
  • Отображение формы с подсвеченными ошибками валидации после ее отправки
  • Редирект на какую-то страницу (обычно это редактирование сущности или список сущностей) после успешной обработки формы

Самое интересное здесь – вторая часть. Когда данные формы приходят в обработчик формы (пользователь нажал кнопку отправки), этот обработчик выполняет "валидацию", то есть проверку введенных данных. Например проверяет что данные в принципе есть, то есть они не пустые. Если данные корректные, то обработка завершается и пользователя отправляют в другое место, но если нет, то Laravel должен отработать эту ситуацию по особенному.

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

Технически, Laravel ведет себя так. Если пользователь ввел что-то некорректно, то происходит редирект на страницу с формой. Laravel автоматически записывает данные формы в сессию и, затем, использует эти данные для подстановки в форму (тут участвует Form::model).

Форма

Как обычно нам придется добавить три вещи: маршрут, обработчик маршрута, шаблон.

Маршрут

<?php

Route::get('/articles/create', '[email protected]')
  ->name('articles.create');

Важно добавить этот маршрут до маршрута /articles/{id}. Иначе последний перехватит обращение к /articles/create, так как он соответствует шаблону.

Обработчик

<?php

namespace App\Http\Controllers;

use App\Article;

class ArticleController extends Controller
{
    // Вывод формы
    public function create()
    {
        // Передаем в шаблон вновь созданный объект. Он нужен для вывода формы через Form::model
        $article = new Article();
        return view('article.create', compact('article'));
    }
}

Шаблон


{{ Form::model($article, ['url' => route('articles.store')]) }}
    {{ Form::label('name', 'Название') }}
    {{ Form::text('name') }}<br>
    {{ Form::label('body', 'Содержание') }}
    {{ Form::textarea('body') }}<br>
    {{ Form::submit('Создать') }}
{{ Form::close() }}

Обработчик данных формы

Маршрут

<?php

// POST запрос
Route::post('/articles', '[email protected]')
  ->name('articles.store');

Обработчик

<?php

namespace App\Http\Controllers;

use App\Article;
// Нам понадобится объект запроса
use Illuminate\Http\Request;

class ArticleController extends Controller
{
    // Здесь нам понадобится объект запроса, для извлечения данных
    public function store(Request $request)
    {
        // Проверка введенных данных
        // Если будут ошибки, то возникнет исключение
        $this->validate($request, [
            'name' => 'required|unique:articles',
            'body' => 'required|min:1000',
        ]);

        $article = new Article();
        // Заполнение статьи данными из формы
        $article->fill($request->all());
        // При ошибках сохранения возникнет исключение
        $article->save();

        // Редирект на указанный маршрут с добавлением флеш сообщения
        return redirect()
            ->route('articles.index');
    }
}

Это первый обработчик, в котором нам понадобился доступ к объекту запроса. Любая информация о HTTP-запросе, любые данные отправленные по HTTP можно получить только через $request.

Как и ранее тут может возникнуть вопрос, каким образом Laravel понимает что в этот метод надо передать объект запроса, а в другие ничего передавать не надо. Ответ кроется в метапрограммировании, которое в PHP делается через Reflection API. Это большая тема, которая разбирается в отдельном курсе

Первым делом объект $request используется в валидации. Валидация в Laravel привязана к запросу. Она выполняется с помощью метода validate($request, $params), доступного в каждом контроллере. Второй аргумент в этом методе – массив, в котором ключ это название поля из формы, а значение, это набор "валидаторов", правил, которые применяются к значению для проверки его корректности. Валидаторы отделяются друг от друга вертикальной чертой. Вот что они означают:

  • require – не может быть пустым
  • min:1000 – минимум 1000 символов
  • unique:articles – поле (name) должно быть уникально в таблице articles

Метод validate ничего не делает если с данными все в порядке и выбрасывает исключение в случае ошибок. Затем Laravel перехватывает это исключение и выполняет всю остальную работу за нас. Он сохраняет данные формы, делает редирект на страницу отображения формы и формирует переменную $errors доступную в шаблоне. Самый простой способ вывести ошибки, добавить над формой такой код:

@if ($errors->any())
    <div>
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif

Вернемся к нашему обработчику. Сразу после валидации выполняется создание сущности, наполнение ее данными формы и сохранение.

<?php

$article = new Article();
$article->fill($request->all())
$article->save();

Метод all() возвращает все данные формы, а метод fill($params) выполняет, так называемый mass-assignment, то есть установку сразу всех значений через передачу ассоциативного массива. Такой способ удобнее чем копировать каждое значение индивидуально:

<?php

// Может получиться много кода!
$article->name = $request->input('name');
$article->body = $request->input('body');

Но mass-assignment обладает одним недостатком, который приходится обрабатывать отдельно. Такой способ установки значений опасен, так как пользователь может послать любые данные, включая те, которых нет в форме (это HTTP, пользователь может отправить все что угодно). Это значит что пользователь может переписать любые данные, включая пароли, идентификаторы и все что угодно, до чего он, по идее, не должен иметь доступ.

Разные фреймворки обрабатывают эту ситуацию по разному. Laravel предлагает создавать внутри модели массив, в котором перечисляются поля, доступные для mass-assignment. Все что там не перечислено будет игнорироваться:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

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

Это легко проверить в Tinker:

>>> $article = new Article();
=> App\Article {#3033}
>>> $article->fill(['name' => 'supername', 'wrongfield' => 'boom!']);
=> App\Article {#3033
     name: "supername",
   }

После того как объект сохранился в базе данных, осталось перенаправить пользователя в то место, куда мы хотим его отправить после успешного создания. Обычно отправка идет на список сущностей или страницу редактирования.

<?php

// Не забудьте сделать return
return redirect()
    ->route('articles.index');

Обратите внимание, что у обработчика данных формы нет своего шаблона. Он в любом случае выполняет редирект: либо на исходную форму, либо на результирующую.

Самостоятельная работа

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

Дополнительные материалы

  1. Валидаторы
  2. Flash-сообщения
Мы учим программированию с нуля до стажировки и работы. Попробуйте наш бесплатный курс «Введение в программирование» или полные программы обучения по Node, PHP, Python и Java.

Хекслет

Подробнее о том, почему наше обучение работает →