Может войдёшь?
Черновики Написать статью Профиль

Основы Laravel 5: Частичные шаблоны и повторное использование форм

перевод Основы Laravel 5 Laracasts

Это перевод видео-урока с Laracasts, серия Laravel 5 Fundamentals, урок №13View Partials and Form Reuse от . Перевод обновлён . Опечатка? Выдели и нажми Ctrl+Enter.

(0:00)
Итак, у нас есть конечный маршрут, показывающий форму для создания новой статьи. Отлично. Но, как вы можете себе представить, нам вероятно понадобится ещё одна форма для ситуаций, когда статью требуется обновить. Так как именно это будет работать? Что же, давайте поговорим о ходе работы и в процессе, у нас будет возможность поговорить о некоторых из лучших практик работы с представлениями. ОК, первый шаг — в нашем файле routes.php нам нужно добавить новый маршрут, показывающий форму для редактирования статьи.

(0:30)
Мы могли бы добавить ещё один маршрут вручную, но, как выясняется, есть специальный тип маршрутов — ресурсный, который мы можем использовать в подобных случаях. Я покажу вам оба метода. Если нам нужно добавить маршрут вручную, то мы могли бы сказать:

PHP
Route::get('article/{id}/edit')

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

(1:00)
Здесь снова мы просто следуем простым практикам REST. Назовём это ArticlesController@edit:

PHP
Route::get('article/{id}/edit''ArticlesController@edit');

Это был ручной способ. Но теперь мы начинаем замечать, что у нас есть ресурс, в данном случае, articles. Нам нужно показать список статей, или форму создания новых статей, или страницу с одной статьёй, или способ сохранения новой статьи, или способ редактирования статей, или способ для её обновления или удаления.

(1:30)
Это основные вещи, которые вы будете часто делать в приложениях типа CRUD. Так что с этим в мыслях, Laravel может сделать для нас всё намного проще. Но прежде, чем мы сделаем это, позвольте мне показать вам новую команду в Artisan. Если мы перейдем в терминал, я могу запустить:

shphp artisan route:list

Я хочу посмотреть все маршруты в моём приложении. Итак, у нас есть эти две статические страницы из первых видео (about, contact), а также те, что относятся к статьям.

(2:00)
Хорошо, но теперь, если мы закомментируем всё это, не забывайте, что это удалит их, так что теперь у нас тут просто есть эти две фиктивные страницы, и теперь я скажу:

PHP
Route::resource('articles''ArticlesController');

ОК, так что теперь, лишь одна строка кода, но если мы запустим это, Laravel автоматически сгенерирует для нас все эти маршруты. И самое главное, обратите внимание, что они полностью соответствуют тому, что мы раньше делали вручную.

(2:30)
И это именно то, что я имею в виду, когда говорю о соблюдении здесь основных соглашений. Так что если мы приводим список всех статей, или создаём статью, или сохраняем её, или выводим на экран, или редактируем, или обновляем, всё это мы рассмотрим в этом уроке. И, наконец, у нас есть маршрут для удаления статьи используя REST. И это означает, что весь этот стандартный код, который может быть полезен в некоторых ситуациях, на самом деле может быть удален в пользу PHPRoute::resource.

(3:00)
Насколько это круто, а? ОК, так что теперь, когда мы рассмотрели оптимизацию маленьких маршрутов, давайте перейдем к PHPArticlesController и создадим этот метод PHPedit(). Так что прямо здесь напишем новый код:

PHP
public function edit()
{

И помните, это показывает страницу для редактирования существующей статьи. Так что мы можем начать с:

PHP
    return view('articles.edit');
}

Однако, если мы редактируем существующую статью, то нам нужно извлечь эту статью из базы данных.

(3:30)
Хорошо:

PHP
$article Article::findOrFail($id);

И не забывайте, что мы здесь можем получить идентификатор в качестве параметра:

PHP
public function edit($id)

Если перейдём обратно в терминал, вот то, на что мы отвечаем. Обратите внимание, у нас тут есть символ-шаблон, который Laravel и будет захватывать. И независимо от того, какое там значение, а в данном случае это идентификатор, оно будет передано в метод PHPedit(). Отлично! Таким образом, мы просто берём этот идентификатор, находим соответствие в таблице статей в нашей базе данных, сохраняем его в PHP$article, и затем, наконец, передаём его в представление:

PHP
return view('articles.edit'compact('article'));

(4:00)
Хорошо, это значит что наш следующий шаг – пойти в views/articles и создать новый файл:

edit.blade.php

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

@extends('app')
@section('content')

Хорошо, так что давайте напишем:

<h1>Edit: {!! $article->title !!}</h1>

(4:30)
Вот так. И прежде чем двигаться дальше, давайте проверим это в браузере. Так:

laravel5.dev/articles/1/edit

И вот оно. Так что теперь нам просто нужно создать форму. Но если подумать, мы уже создали здесь форму (create.blade.php), так что же нам дублировать всё это? И если задуматься, нам, вероятно, будут нужны ошибки для формы обновления, так что хм...

(5:00)
Что же, прямо сейчас, давайте просто скопируем это, чтобы всё просто заработало, а затем, после этого, я покажу вам некоторые способы оптимизации, чтобы нам больше не беспокоиться о повторении кода. Хорошо, мы идём на страницу редактирования. Я вставлю здесь это, но на этот раз URL будет немного другим. Куда мы хотим чтобы эта форма отправляла информацию? И тут стоит узнать немного побольше о REST. Вот здесь мы редактируем статью, и когда отправляем эту форму, по соглашению нужно делать PATCH-запрос к articles/{articles}.

(5:30)
А идея, обратите внимание, в том, что, когда мы следуем этому основному соглашению (имя коллекции, а затем идентификатор), то если мы используем тип запроса, не важно GET, или POST или PUT, или DELETE, если мы используем их соответственно тому, что мы собираемся сделать, то мы ограничиваем количество адресов URI, которые нам необходимо создать. Больше у вас нет конечных точек типа Articles/updateArticle.php или deleteArticle.php.

(6:00)
Все эти старые, унаследованные из прошлого вещи не должны нас больше беспокоить. Это хорошее соглашение, которому стоит следовать. Хорошо, мы знаем, что мы хотим тип запроса PATCH и что URL будет вот таким. Так что мы можем установить метод PATCH. И теперь ещё раз, мы могли бы либо использовать URL вроде articles/, а затем ID статьи:

PHP
{!! Form::open(['method' => 'PATCH''url' => 'articles/' $article->id]) !!}

Вы могли бы сделать так. Или вы могли бы использовать маршруты, если вы забежали немного вперёд и узнали об именных маршрутах.

(6:30)
Или вы могли бы использовать действие (action). Почему мы бы нам на этот раз не использовать его для разнообразия? Так какое действие или метод на контроллере мы хотим вызвать?

PHP
{!! Form::open(['method' => 'PATCH''action' => 'ArticlesController@update']) !!}

Тем не менее, есть одна вещь, которую стоит иметь в виду и не забывать. Давайте переключимся обратно к нашим маршрутам. Если мы хотим отправить PATCH-запрос, то мы также должны послать этот шаблон {articles}. Нам нужно сообщить Laravel о каком PHP$article->id мы здесь говорим. И пока что мы ещё не сделали этого.

(7:00)
Таким образом, мы можем это изменить, обернув это, поместив внутрь массива, а затем передать дальше. Вот так:

PHP
{!! Form::open(['method' => 'PATCH''action' => ['ArticlesController@update'$article->id]]) !!}

Так что, как я уже говорил, если вам нравится этот подход, используйте его. Или, если вы хотите использовать именные маршруты, то делайте это. Или, если вы просто хотите писать URL вручную, то вы можете и это сделать. Любой из этих методов будет работать. Я просто даю вам знать, что у вас здесь есть выбор. Хорошо, давайте взглянем на форму. Я обновлю страницу, всё выглядит хорошо. Очень похоже на то, что у нас было раньше. Но теперь, если я посмотрю в исходный текст, мы можем увидеть, что, да, действие (action) верное.

(7:30)
А также, на самом деле мы не можем устанавливать любые типы запроса в браузерах. Поэтому мы как бы должны сфальсифицировать его. И вот для чего здесь этот маленький раздел. Laravel добавит скрытый входной параметр, который по сути говорит ему, в запросе какого типа мы тут заинтересованы. В этом случае, это PATCH. Так что мы внедрим это в форму, но скроем от пользователя, поскольку, конечно же, ему не нужно этого видеть. И, наконец, у нас здесь есть небольшой токен для защиты от атак с использованием кросс-сайтовых запросов (CSRF).

(8:00)
И Laravel автоматически добавит его для вас, что очень удобно. ОК, всё становится на свои места, но у нас тут конечно же есть ещё одна проблема. Мы пытаемся редактировать статью, но я не вижу ни существующий заголовок, ни тело, ни дату, когда она была опубликована. Это наш следующий шаг. Так давайте перейдём обратно в нашу форму, и мы воспользуемся тем, что мы называем привязкой модели к форме (form model binding). Это очень просто, не волнуйтесь. Мы привяжем модель Eloquent к форме.

(8:30)
Все, что мы здесь делаем, это изменяем PHPopen() на PHPmodel(), а затем передаём наш объект:

PHP
{!! Form::model($article, ['method' => 'PATCH''action' => ['ArticlesController@update'$article->id]]) !!}

ОК, давайте посмотрим на разницу. Обновим и проверим. С помощью привязки модели формы эти значения автоматически применяются ко входным данным, что очень даже здорово. Так что теперь мы можем сделать наше изменение. И ещё несколько вещей. Одна из них, мы по-прежнему ставим по умолчанию сегодняшний день, т.е. время этой записи, а не момент установки поля published_at.

(9:00)
И это потому, что нам нужно добавить accessor, который убедится в том, что мы преобразовали значение из базы данных в нужный формат для ввода даты в HTML5. Но вы знаете, пока что мы проигнорируем данную деталь. Я предпочел бы доделать нашу задачу, так как у нас есть ещё пара моментов о которых следует поговорить. Дальше, я нажму «Добавить статью», но этот текст не является правильным. На кнопке должно быть «Обновить статью», не так ли? Хорошо, просто имейте это в виду, и давайте попробуем. Так что мы запускаем, и... блин, у нас нет для этого нужного метода.

(9:30)
Так что это наш следующий очевидный шаг. PHPArticlesController. Далее мы добавим метод для PHPupdate(). И снова, он получит PHP$id статьи, которую мы хотим обновить:

PHP
public function update($id)
{

Так что ещё раз, мы отслеживаем эту статью. И затем, мы обновим её, используя значения из этой формы. Так:

PHP
$article->update($request->all());

(нам снова нужно получить PHP$request, так что мы хотим сделать что-то подобное)

(10:00)
Это означает, что мы могли бы создать новый запрос формы, или, по крайней мере, для начала, давайте просто будем ссылаться на обычный объект PHPRequest, например, так:

PHP
public function update($idRequest $request)

Теперь, здесь вы можете подумать: «Как же это работает? Откуда Laravel узнает, что здесь должен быть символ-шаблон, а здесь что-то ещё?». И это работает потому, что, не вдаваясь в подробности, Laravel 5 предлагает то, что мы называем Method Injection (внедрение через метод). Пока мы используем подсказки типов, Laravel будет работать с ними через рефлексию (reflection)...

(10:30)
Он выяснит: «ОК, они хотят объект PHP$request, я создам экземпляр объекта и передам его им». И это будет верно для любого объекта в вашем приложении. Это одна из встроенных особенностей Laravel. Но также, когда он обнаруживает этот PHP$id, то по сути не имеет никакого значения, является ли PHP$id первым или вторым параметром. Laravel достаточно умен чтобы выяснить всё это самостоятельно. Довольно круто. ОК, так что теперь давайте посмотрим, как всё это работает.

(11:00)
Мы находим нашу статью, мы обновляем её, и далее давайте перенаправим назад к странице со списком статей articles:

PHP
return redirect('articles');

Хорошо, итак, вот где мы были раньше. Мы нажмём «Добавить статью», которая на самом деле должна быть «Обновить статью», и готово. Мы можем увидеть что изменение произошло. Так давайте напишем ещё один раз. One more. Обновим её, и всё работает так, как мы и ожидали. Круто. Но теперь нам нужно решить ещё две вещи. Во-первых, в этой форме у нас нет никакой проверки вводимых данных. И во-вторых, мы до сих пор создаём две отдельные формы.

(11:30)
Один набор кода для создания статьи, и другой набор кода для обновления статьи. Если получится, я предпочел бы просто импортировать одну форму в оба представления. Хорошо, давайте сначала решим задачу проверки входных данных. И здесь мы можем поступить немного стратегически. Так что, если мы вернёмся в Http/Requests, у нас тут есть PHPCreateArticleRequest, поэтому у нас есть эти правила, определенные прямо здесь. И ещё раз, если мы сможем так сделать, я предпочитаю не создавать ещё один запрос под названием PHPUpdateArticleRequest.

(12:00)
Так что, один из вариантов — мы могли бы переместить эти правила в небольшой защищенный (protected) метод на нашем контроллере, а затем использовать встроенный типаж (trait) проверки входных данных непосредственно в нём. Или мы могли бы переименовать это в нечто чуть более общее, а затем использовать это из разных мест. Как насчёт PHPArticleRequest, и теперь, если мы перейдём назад к нашему контроллеру, мы обновим всё прямо здесь. И давайте пойдём к верху страницы и изменим здесь. Хорошо, теперь, я буду также ссылаться на него вот здесь.

(12:30)
Таким образом, мы сможем использовать его в двух местах. И вот главная вещь, которую нужно понять – в некоторых ситуациях, ваши правила проверки входных данных будут отличаться для Update по сравнению с Create. В таких ситуациях вы должны решить, может мне стоит просто создать новый запрос формы? Или, так как PHPrules() представляет собой метод и не является массивом, то вы можете сделать быструю проверку, просматриваете ли вы какой-то символ-шаблон для маршрута или вашего URL-сегмента.

(13:00)
Вы можете делать здесь любой тип проверки и затем динамически обновить это. Например, вы установите PHP$rules, и в конечном итоге вернёте его, а затем вы можете сделать проверку вроде:

PHP
if ($condition) {

Проверить сегмент URL или что угодно. Затем добавить к правилам. Так:

PHP
$rules['something_else'] = 'required'

Или, если вы хотите удалить что-нибудь или сделать необязательным, то у вас здесь есть достаточно гибкости. Всё понятно? Так что давайте просто приведём всё это обратно к тому, как у нас тут было раньше.

(13:30)
И теперь, если я переключусь обратно в PHPArticlesController, это должно быть достаточно хорошо. И я думаю, что PhpStorm здесь сходит с ума абсолютно без каких-либо причин. Так что пока просто игнорируйте это. У нас есть объект PHP$request, он не отсутствует. Так что, я думаю, у нас всё готово к запуску. Конечно же, мы также должны изменить тут имя. И попробуем это в браузере. Итак, вернёмся сюда, скажем «Ещё один раз», отправим и, кажется, всё работает. Но теперь, давайте отредактируем здесь и сделаем так, чтобы валидация дала отрицательный результат.

(14:00)
Мы оставим здесь пустые поля, отправим форму, и как видите, теперь это работает. Хорошо, таким образом мы очень легко расширили эту форму запроса. Но теперь, чтобы закончить урок, у нас до сих пор есть проблема с тем, что у нас есть два разных набора кода для одной и той же формы. Вместо этого мы будем использовать partials, чтобы подчистить это. Итак, давайте начнём. Если мы перейдем в articles/create, заметьте что прямо здесь внизу у нас есть раздел для отображения ошибок.

(14:30)
А также внутри страницы edit.blade.php, у нас есть та же самая вещь. Так что похоже, имеем ли мы дело со статьёй или каким-либо другим видом ресурсов, в большинстве приложений у вас будет некоторый раздел, где можно было бы выкладывать любые ошибки в формах. Так почему бы нам не перенести это и не создать папку? Здесь у нас уже есть папка errors, так что её будет достаточно:

list.blade.php

И я вставлю это сюда. Теперь, если мы переключимся назад, мы можем здесь всё удалить и заменить на:

@include ('')

(15:00)
Теперь, когда мы вызываем @include(), ваш каталог views будет использоваться в качестве основного. И это значит, что я могу просто сказать:

@include ('errors/list')

Не забывайте, что мы ещё можем использовать псевдоточечную нотацию, которая выглядит немного чище. И это означает, что мы можем сделать то же самое для представления create.blade.php. Так что, мы оптимизируем наш код, и если мы попытаемся запустить его ещё раз, то он всё ещё должен работать, и да, всё работает. Круто. Так что дальше, мы можем сделать то же самое для формы.

(15:30)
Но вот о чём мы тут ещё должны подумать. Не забывайте, что некоторые вещи будут отличаться в форме для создания от формы для редактирования. Например, в articles/create мы хотим кнопку с надписью «Добавить статью». А также, в самом теге формы, некоторые атрибуты будут уникальными для процесса сохранения статьи. Когда же мы редактируем статью, мы хотим кнопку с надписью «Обновить статью». И опять же тег формы будет отличаться.

(16:00)
ОК, так что, возможно, мы могли бы сделать вот что. Мы могли бы сделать обёртывающий раздел, как в PHPForm::open() и PHPForm::close(), мы просто это продублируем. Но тогда внутренности, так сказать, могут быть помещены в partial, потому что тот раздел не изменяется. Так:

@include('articles.partials')

И вы можете поместить это в partial, если захотите. Некоторые люди так и делают. Таким образом, вы бы могли создать папку partials и всё связанное с ними было бы там. Или, если вы хотите сделать form, это тоже было бы хорошо.

(16:30)
Или же, некоторые люди любят использовать подчеркивание, чтобы обозначить, что это не полное представление, а только частичное, который импортируется в представление. Таким образом, вы можете следовать любому из этих соглашений. Мы пока сделаем всё очень просто и создадим его:

form.blade.php

Форма для статьи. И мы можем избавиться от этих комментариев. Красиво и чисто. Но дальше, что насчёт вот этого раздела? И я предпочитаю не переносить его.

(17:00)
Я действительно не хочу делать это в каждом разделе, несмотря на то что могу. Я хочу чтобы всё было довольно чисто, вот так. Так что мы можем сделать? Ну, может быть, если я верну это обратно, мы могли бы сохранить это как переменную, например PHP$submitButton.
Так что теперь, если мы вернемся к Create, мы включим эту форму, и важно понимать, что, когда вы включаете форму, содержимое этого файла будет иметь доступ к внешнему миру. Поэтому всё, что было доступно в этом представлении, конечно же, также будет доступно, как только вы включите форму.

(17:30)
Так уж это работает. Но также, если мы хотим передать какие-либо переменные, например:

PHP
['submitButtonText' => 'Add Article']

И мы могли бы сделать это. И теперь это будет здесь трактоваться как переменная. Хорошо, давайте посмотрим, если это работает. Обновите и вы опять получите точно такую же вещь, но теперь мы можем её контролировать. Хорошо, круто.

(18:00)
Так что давайте сделаем то же самое для формы редактирования и почистим тут всё это дело. Итак, вернём это обратно. Сделаем:

PHP
@include ('articles.form', ['submitButtonText' => 'Update Article'])

И на этот раз, текст кнопки гласит «Обновить статью». Это один из способов справиться с этой задачей. Итак, давайте проверим это.

laravel5.dev/articles/1/edit

и теперь всё работает. Так, My Revised First Article... и, как вы можете видеть, всё тут работает. Действительно крутая штука.

(18:30)
ОК, я думаю, здесь мы и остановимся для этого урока. Но обратим внимание на всё, что мы узнали за такой короткий период времени. Раз, вы узнали о том, как создавать частичные шаблоны. Это так же просто, как и создание файла, вставка строк HTML-кода, и затем включение его в другое представление. Вы также узнали, как передавать переменные, к которым представлению может понадобиться доступ. Далее, в процессе использования partials, вы узнали, как повторно использовать формы, так чтобы мы не повторялись снова и снова.

(19:00)
Вы можете представить себе ситуацию, в которой, если вы не делали этого, то когда мы добавляем новое поле в таблицу, вам придётся изменять форму в двух разных местах. Не очень хорошая идея. И, наконец, если перейдём обратно к PHPArticlesController, мы говорили о том, насколько может быть полезным в некоторых ситуациях использовать более общий класс формы запроса. Таким образом, мы можем использовать PHPArticleRequest для обоих действий, создания и обновления.

(19:30)
И потом, я чуть не забыл самую последнюю вещь, вы узнали, как избавиться от большого объёма ручной работы в ситуациях, когда простой ресурсный маршрут является лучшим вариантом.
Таким образом, мы рассмотрели много интересного материала в этом видео. Если нужно, пересмотрите его снова. И потом давайте двигаться дальше.

Как вы считаете, полезен ли этот материал? Да Нет

Комментарии (4)

Nik0ne

Если при попытки отредактировать статью у вас вылетает ошибка, то возможно вам нужно в ArticlesController добавить use Illuminate\Http\Request;

AlexNavidu

Если поступить как вы предлагаете, тогда возможны проблемы с методом store - если вы использовали (Request::all()).

Нужно всего лишь поступить так. $request->all заменить на $request::all

zZz

Спасибо $request::all помог, авторизовался чтобы поблагодарить)

AlexNavidu

Пожалуйста)

Написать комментарий

Разметка: ? ?

Авторизуйся, чтобы прокомментировать.