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

Основы Laravel 5: Выбор тегов в UI

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

Это перевод видео-урока с Laracasts, серия Laravel 5 Fundamentals, урок №22Selecting Tags From the UI от . Перевод обновлён . Опечатка? Выдели и нажми Ctrl+Enter.

(0:00)
В последнем видео вы узнали об отношениях многие-ко-многим, и о том, как мы можем создавать сводные таблицы (pivot tables) и изображать их с помощью Eloquent. Так что теперь давайте прицепим всё это к нашему пользовательскому интерфейсу. Я думаю, прямо тут, ниже даты публикации, мы добавим список с множественным выбором, в котором пользователи смогут выбирать теги, которые они хотят применить к этой статье. Давайте начнём. Просто чтобы освежить нашу память из articles/create мы включаем partial нашей формы. Давайте перейдём туда.

(0:30)
Хорошо, здесь мы добавим наше текстовое поле для тегов, но на самом деле это должен быть элемент select. Порядок параметров здесь немного иной, у нас есть имя выбранного элемента, значения по умолчанию, я жёстко пропишу второй параметр (hardcode), а третьим параметром будет выбранный вариант в списке. И далее у нас есть любые дополнительные атрибуты, которые нужно применить к элементу:

PHP
{!! Form::label('tags''Tags:') !!}
{!! 
Form:select('tags', ['defaults'], null, ['class' => 'form-control']) !!}

(1:00)
Итак, позвольте мне показать вам, как это выглядит. Мы переключаемся в Chrome, и да, у нас есть элемент выбора, содержащий только лишь то жёстко-прописанное значение. Но, как я уже говорил, я хочу, чтобы здесь был множественный выбор, чтобы вы могли применить несколько тегов к вашей статье. ОК, чтобы это исправить, я добавлю атрибут multiple к элементу выбора. Так что если я вернусь и обновлю страницу, теперь мы получаем кое-что другое. И если мы посмотрим в исходный код, то вы увидите, что наш атрибут был применён вот здесь.

(1:30)
OK, далее, мы, конечно же, не хотим жёстко-прописанные значения. Так что на самом деле это должно выглядеть как список тегов, не так ли? Ну, может быть, я назову это PHP$tags, а затем передам его дальше. Давайте посмотрим, как это может выглядеть. Мы идём к нашему методу PHPcreate(), мы извлекаем наши метки:

PHP
$tags = \App\Tag::all();

и мы могли бы получить их все, но, как вы узнали в последнем видео, у нас на самом деле есть метод под названием PHPlists():

PHP
$tags = \App\Tag::lists('name');

дайте мне массив всех значений из столбца, допустим, name.

(2:00)
Хорошо, так почему бы нам не пойти дальше и не импортировать это? Передадим это в вид:

PHP
return view('articles.create'compact('tags'));

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

shphp artisan thinker

и затем:

PHP
\App\Tag::create(['name' => 'work']);

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

(2:30)
Но это даст вам хороший пример. Мы уже немного говорили об уязвимостях связанных с массовым назначением, и о том, что Laravel держит нас в безопасности. В данном случае мы пытаемся передать name для метода PHPcreate(), но мы не позволяем это, поскольку по сути оно занесено в чёрный список. И в результате бросается исключение. Если мы вернёмся, давайте перейдём к нашей модели PHPTag, мы можем сейчас здесь её обновить. Заполняемым полем для PHPTag пока что будет name:

PHP
protected $fillable = [
    
'name'
];
* Заполняемые поля для тега.

Хорошо, теперь я думаю, мы можем попробовать ещё раз.

(3:00)
И готово. Давайте добавим ещё один или, может быть парочку, может быть food, и как насчёт coding?

PHP
\App\Tag::create(['name' => 'food']);
\
App\Tag::create(['name' => 'coding']);

ОК, так что теперь, если мы сделаем:

PHP
\App\Tag::lists('name');

мы получим массив из 4 элементов. Но на самом деле это даёт мне хорошую возможность показать вам кое-что ещё. Когда мы передаём этот массив в наш список опций для этого элемента select, их значения (option values) будут просто установлены в индекс этого массива.

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

PHP
\App\Tag::lists('name''name');

ОК, мы заметим, что поле name будет установлено равным ключу. И в конечном счете, это именно то, что мы хотим. Так что давайте вернёмся к нашему контроллеру здесь и обновим вот это:

PHP
$tags Tag::lists('name''name');

Класс.

(4:00)
Теперь здесь, в нашем виде для формы мы передаем этот массив всех тегов нашего приложения в поле выбора. Надеюсь это должно заработать. Так что я вернусь в Chrome, обновлю и готово. И если мы хотим выбрать более одного тега, то нам лишь нужно сделать Cmd+ или Ctrl+клик. Хорошо, но есть ещё одна вещь, которую мы должны принять к сведению. Если я переключусь обратно на PHPArticlesController, когда мы отправляем форму, я просто хочу показать вам, что мы здесь получим. Так что давайте отделим значение от этого поля выбора тегов:

PHP
dd($request->input('tags'));

(4:30)
Хорошо, давайте заполним это, и я выберу их здесь все. Но обратите внимание, когда я нажал на кнопку, то только один из них был передан. Кажется все остальные были проигнорированы. И это потому, что мы должны работать с ним как с массивом. Так что, если мы вернёмся к форме, всё, что мы должны сделать, чтобы это заработало, это поменять вот здесь (tags[]). Это всё, что мы должны сделать.
Хорошо, давайте вернёмся, обновим и попробуем снова. Но на этот раз вы увидите, мы действительно получаем массив.

(5:00)
Отлично, это именно то, что мы хотим. Хорошо, давайте подумаем об этом. Мы отправляем форму, и теперь у нас есть массив тегов, которые мы хотим связать с этой конкретной статьёй. И вы уже знаете как использовать метод PHPattach() для создания новой записи в нашей сводной таблице. Так что похоже, что у нас есть всё, что нам здесь нужно. Давайте попробуем:
Я переключусь к нашему PHPArticlesController. Для начала, давайте будем здесь слегка многословными, а потом сделаем рефакторинг в конце видео.

(5:30)
Итак, мы хотим получить все теги, и мы знаем что можем сделать:

PHP
$tags $request->input('tags');

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

PHP
$articles->tags()->attach([1234])

мы передаём массив всех идентификаторов тегов, с которыми мы хотим их связать. Но сейчас у нас есть просто имя тега.

(6:00)
Могли бы мы вместо этого просто установить это равным идентификатору тега? Давайте посмотрим, как это может выглядеть. На этот раз я снова сделаю PHPdd(), но вы увидите, что итог будет несколько иным:

PHP
dd($request->input('tags'));

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

(6:30)
Я могу изменить это на PHP$tagIds и тогда мы можем сказать PHP$article... но где мне взять мою статью? Мы создали её вот здесь и она будет возвращена нам, так что мы сможем сделать это. Теперь я могу сказать:

PHP
$article->tags()->attach($tagIds);

и, наконец, почему бы нам не убрать эту переменную? И вы знаете, на этом всё! Таким образом, мы начинаем с создания статьи и связывания её с аутентифицированным пользователем, а затем мы обновляем сводную таблицу.

(7:00)
Мы говорим PHP$article для этой сводной таблицы PHPtags(), я хочу связать её и использовать в частности, идентификатор этой статьи с этим массивом тегов. Поэтому обратите внимание, когда мы вызываем PHPattach(), вы можете передать целое число, идентификатор или массив идентификаторов. Так что я думаю, теперь мы готовы попробовать это по-настоящему. Давайте напишем Some Personal Article (Какая-то личная статья), вставим здесь фиктивный текст, и присвоим ей тег personal, и допустим coding.

(7:30)
ОК, мы добавляем статью. Всё сработало, если мы нажимаем на неё, то ещё не можем этого видеть, но давайте удостоверимся, что это сработало.

shphp artisan tinker

и мы хотим статью с idавным 15:

PHP
$article = \App\Article::find(16);

потом скажем:

PHP
$article->tags->toArray();

вот они – coding и personal. Так что теперь, когда мы знаем, что это работает, почему бы нам не отобразить их на странице?

(8:00)
Я переключусь на вид articles/show, и затем как насчёт того, чтобы прямо здесь нам вставить теги:

<h5>Tags:</h5>

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

PHP
<ul>
@foreach (
$article->tags as $tag)
<
li>{{ $tag->name }}</li>
</
ul>

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

(8:30)
Хорошо, давайте перейдём обратно в браузер:

laravel5.dev/articles/16

обновим и готово. Вот наши теги. Но как насчёт какой-нибудь другой статьи?

laravel5.dev/articles/4

У нас нет здесь никаких тегов, но мы всё ещё видим надпись. Может быть, это нормально, или может быть, вы хотите проверить здесь, если у нас есть какие-то теги, то мы скажем, если это не пусто, т.е. @unless наш список тегов пуст, то отобразить их:

PHP
@unless ($article->tags->isEmpty())
...
@
endunless

Запомните, стоит думать об @unless как об эквиваленте IF NOT (если не).

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

(9:30)
В этом видео мы просто пойдём по пути дублирования кода. Но я хочу, чтобы вы подумали о том, как было бы здорово, если бы был способ связать переменные с любым видом, даже если бы это был partial, который мы хотим включить? На самом деле есть такой способ, но мы пока не будем его рассматривать. Так что давайте вернёмся к PHPArticlesController и если мы пойдём к методу PHPcreate(), мы захватили наши тэги. Так почему бы нам ещё раз просто не сделать то же самое временно вот здесь, в PHPеdit(), и затем передаём дальше:

PHP
$tags Tag::lists('name''id');
return 
view('articles.edit'compact('article''tags'));

(10:00)
OK, обновим и теперь она отображается, но у нас есть новая проблема.
Мы знаем, что у этой статьи есть 2 тега, personal и coding, но они здесь не отражены. Так как же нам это сделать? Давайте перейдём обратно в форму. Вы помните, что для нашего метода PHPselect() мы передали имя и различные опции, а затем, под конец идёт то, что следует рассматривать в качестве выбранного значения, и вы здесь можете передать строку или массив.

(10:30)
Так, например, если мы хотим, рассматривать тег с идентификатором 1 как выбранный, то вот, пожалуйста. Или как насчет другого? Как насчет coding, который имеет id равным 5? ОК, тогда мы можем сказать, 1 и 5 — [1, 5]. Обновим и теперь вы видите, как это работает, не так ли?
Так что похоже нам нужно найти способ, чтобы связать это. И у нас есть несколько решений.

(11:00)
Вы можете вызвать какой-нибудь метод вроде PHP$article->tagsList() непосредственно на статье, чтобы получить выбранные значения. Но мы используем привязку модели к форме, так что было бы здорово, если бы мы могли сделать что-то вроде этого:

PHP
public function getTagsAttribute()

Мы могли бы использовать метод вроде PHPgetTagsAttribute(), но это уже не будет работать, потому что если мы это перезапишем и вернём массив или что-то типа того, то каждый раз, когда мы попытаемся использовать PHP$article->tags() в наших разных файлах, то он больше не будет работать, не так ли? Поскольку мы перезаписали его.

(11:30)
Тогда, возможно, мы могли бы использовать что-то вроде PHPgetTagListAttribute(). Хорошо? И когда мы будем говорить tagList или tag_list, то этот метод будет срабатывать. Тогда мы могли бы:

PHP
return $this->tags->lists('id');

получить массив идентификаторов тегов, связанных с этой статьей. Хорошо, мы скажем:

* Получить список идентификаторов тегов,  связанных с текущей статьей.

и это должно будет вернуть нам массив.

(12:00)
Теперь, если мы перейдём обратно к form.blade.php, мы можем изменить здесь с tags на tag_list.
Далее я могу возвращать здесь null, поскольку привязка модели позаботится об этом за меня. И чтобы доказать это вам, давайте вернёмся в браузер, обновим, и вот смотрите. Всё работает. Но только помните, мы изменили имя, так что давайте вернёмся к PHPArticlesController, где мы делаем PHPstore() для новой статьи и поправим здесь код соответствующим образом.

(12:30)
Хорошо, всё начинает выглядеть довольно здорово. Почему бы нам не запустить процесс с нуля чтобы увидеть поток работ? На этот раз это будет Some Other Work Related Article (Ещё одна статья связанная с работой), добавим текст, и тегами здесь будут work и food. Хорошо, добавим статью, посмотрите на неё, у неё есть эти 2 тега, и если мы попытаемся её изменить, то они будут здесь выбраны.
Всё очень круто, но я здесь оставлю вас с небольшой интригой.

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

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

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

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

KOROLKOV

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

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

Разметка: ? ?

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