(0:00)
В последнем видео вы узнали об отношениях многие-ко-многим, и о том, как мы можем создавать сводные таблицы (pivot tables) и изображать их с помощью Eloquent. Так что теперь давайте прицепим всё это к нашему пользовательскому интерфейсу. Я думаю, прямо тут, ниже даты публикации, мы добавим список с множественным выбором, в котором пользователи смогут выбирать теги, которые они хотят применить к этой статье. Давайте начнём. Просто чтобы освежить нашу память из articles/create мы включаем partial нашей формы. Давайте перейдём туда.
(0:30)
Хорошо, здесь мы добавим наше текстовое поле для тегов, но на самом деле это должен быть элемент select. Порядок параметров здесь немного иной, у нас есть имя выбранного элемента, значения по умолчанию, я жёстко пропишу второй параметр (hardcode), а третьим параметром будет выбранный вариант в списке. И далее у нас есть любые дополнительные атрибуты, которые нужно применить к элементу:
{!! Form::label('tags', 'Tags:') !!}
{!! Form:select('tags', ['defaults'], null, ['class' => 'form-control']) !!}
(1:00)
Итак, позвольте мне показать вам, как это выглядит. Мы переключаемся в Chrome, и да, у нас есть элемент выбора, содержащий только лишь то жёстко-прописанное значение. Но, как я уже говорил, я хочу, чтобы здесь был множественный выбор, чтобы вы могли применить несколько тегов к вашей статье. ОК, чтобы это исправить, я добавлю атрибут multiple к элементу выбора. Так что если я вернусь и обновлю страницу, теперь мы получаем кое-что другое. И если мы посмотрим в исходный код, то вы увидите, что наш атрибут был применён вот здесь.
(1:30)
OK, далее, мы, конечно же, не хотим жёстко-прописанные значения. Так что на самом деле это должно выглядеть как список тегов, не так ли? Ну, может быть, я назову это PHP$tags
, а затем передам его дальше. Давайте посмотрим, как это может выглядеть. Мы идём к нашему методу PHPcreate()
, мы извлекаем наши метки:
$tags = \App\Tag::all();
и мы могли бы получить их все, но, как вы узнали в последнем видео, у нас на самом деле есть метод под названием PHPlists()
:
$tags = \App\Tag::lists('name');
дайте мне массив всех значений из столбца, допустим, name.
(2:00)
Хорошо, так почему бы нам не пойти дальше и не импортировать это? Передадим это в вид:
return view('articles.create', compact('tags'));
и давайте посмотрим, что тут получилось. Итак, вернёмся к Chrome, обновим страницу, и в данном случае у нас здесь просто один тег. Так что вот оно. Имея это в виду, почему бы нам не создать несколько тегов за кадром?
shphp artisan thinker
\App\Tag::create(['name' => 'work']);
но знаете что? Мне только что пришла в голову мысль, я думаю, что это не сработает, и да, здесь ошибка.
(2:30)
Но это даст вам хороший пример. Мы уже немного говорили об уязвимостях связанных с массовым назначением, и о том, что Laravel держит нас в безопасности. В данном случае мы пытаемся передать name для метода PHPcreate()
, но мы не позволяем это, поскольку по сути оно занесено в чёрный список. И в результате бросается исключение. Если мы вернёмся, давайте перейдём к нашей модели PHPTag
, мы можем сейчас здесь её обновить. Заполняемым полем для PHPTag
пока что будет name:
protected $fillable = [
'name'
];
* Заполняемые поля для тега.
Хорошо, теперь я думаю, мы можем попробовать ещё раз.
(3:00)
И готово. Давайте добавим ещё один или, может быть парочку, может быть food, и как насчёт coding?
\App\Tag::create(['name' => 'food']);
\App\Tag::create(['name' => 'coding']);
ОК, так что теперь, если мы сделаем:
\App\Tag::lists('name');
мы получим массив из 4 элементов. Но на самом деле это даёт мне хорошую возможность показать вам кое-что ещё. Когда мы передаём этот массив в наш список опций для этого элемента select, их значения (option values) будут просто установлены в индекс этого массива.
(3:30)
То есть 0, 1, 2 и 3. Но на самом деле я хочу, чтобы значение опции было таким же, как сам текст, и я опишу это немного больше, когда мы дойдём до этого. Но пока что, заметьте что произойдёт, если мы передадим второй параметр, вот так:
\App\Tag::lists('name', 'name');
ОК, мы заметим, что поле name будет установлено равным ключу. И в конечном счете, это именно то, что мы хотим. Так что давайте вернёмся к нашему контроллеру здесь и обновим вот это:
$tags = Tag::lists('name', 'name');
(4:00)
Теперь здесь, в нашем виде для формы мы передаем этот массив всех тегов нашего приложения в поле выбора. Надеюсь это должно заработать. Так что я вернусь в Chrome, обновлю и готово. И если мы хотим выбрать более одного тега, то нам лишь нужно сделать Cmd+ или Ctrl+клик. Хорошо, но есть ещё одна вещь, которую мы должны принять к сведению. Если я переключусь обратно на PHPArticlesController
, когда мы отправляем форму, я просто хочу показать вам, что мы здесь получим. Так что давайте отделим значение от этого поля выбора тегов:
dd($request->input('tags'));
(4:30)
Хорошо, давайте заполним это, и я выберу их здесь все. Но обратите внимание, когда я нажал на кнопку, то только один из них был передан. Кажется все остальные были проигнорированы. И это потому, что мы должны работать с ним как с массивом. Так что, если мы вернёмся к форме, всё, что мы должны сделать, чтобы это заработало, это поменять вот здесь (tags[]). Это всё, что мы должны сделать.
Хорошо, давайте вернёмся, обновим и попробуем снова. Но на этот раз вы увидите, мы действительно получаем массив.
(5:00)
Отлично, это именно то, что мы хотим. Хорошо, давайте подумаем об этом. Мы отправляем форму, и теперь у нас есть массив тегов, которые мы хотим связать с этой конкретной статьёй. И вы уже знаете как использовать метод PHPattach()
для создания новой записи в нашей сводной таблице. Так что похоже, что у нас есть всё, что нам здесь нужно. Давайте попробуем:
Я переключусь к нашему PHPArticlesController
. Для начала, давайте будем здесь слегка многословными, а потом сделаем рефакторинг в конце видео.
(5:30)
Итак, мы хотим получить все теги, и мы знаем что можем сделать:
$tags = $request->input('tags');
и это будет массив со всеми тегами что пользователь может добавить к статье. Но дальше задумайтесь, нам нужны идентификаторы этих тегов, потому что в конечном счете мы будем делать что-то вроде этого:
$articles->tags()->attach([1, 2, 3, 4])
мы передаём массив всех идентификаторов тегов, с которыми мы хотим их связать. Но сейчас у нас есть просто имя тега.
(6:00)
Могли бы мы вместо этого просто установить это равным идентификатору тега? Давайте посмотрим, как это может выглядеть. На этот раз я снова сделаю PHPdd()
, но вы увидите, что итог будет несколько иным:
dd($request->input('tags'));
Идём обратно в браузер, обновим, добавим новую статью. Я выберу все теги, и теперь мы получаем только идентификаторы тегов, и на самом деле это именно то, что мы хотим в данном случае. Так что это сделает всё для нас намного проще.
(6:30)
Я могу изменить это на PHP$tagIds
и тогда мы можем сказать PHP$article
... но где мне взять мою статью? Мы создали её вот здесь и она будет возвращена нам, так что мы сможем сделать это. Теперь я могу сказать:
$article->tags()->attach($tagIds);
и, наконец, почему бы нам не убрать эту переменную? И вы знаете, на этом всё! Таким образом, мы начинаем с создания статьи и связывания её с аутентифицированным пользователем, а затем мы обновляем сводную таблицу.
(7:00)
Мы говорим PHP$article
для этой сводной таблицы PHPtags()
, я хочу связать её и использовать в частности, идентификатор этой статьи с этим массивом тегов. Поэтому обратите внимание, когда мы вызываем PHPattach()
, вы можете передать целое число, идентификатор или массив идентификаторов. Так что я думаю, теперь мы готовы попробовать это по-настоящему. Давайте напишем Some Personal Article (Какая-то личная статья), вставим здесь фиктивный текст, и присвоим ей тег personal, и допустим coding.
(7:30)
ОК, мы добавляем статью. Всё сработало, если мы нажимаем на неё, то ещё не можем этого видеть, но давайте удостоверимся, что это сработало.
shphp artisan tinker
и мы хотим статью с idавным 15:
$article = \App\Article::find(16);
$article->tags->toArray();
вот они – coding и personal. Так что теперь, когда мы знаем, что это работает, почему бы нам не отобразить их на странице?
(8:00)
Я переключусь на вид articles/show, и затем как насчёт того, чтобы прямо здесь нам вставить теги:
<h5>Tags:</h5>
это не будет самым красивым решением, но будет работать. Так что мы скажем:
<ul>
@foreach ($article->tags as $tag)
<li>{{ $tag->name }}</li>
</ul>
и позже, возможно, в следующем видео, я покажу вам, как превратить это в ссылку, так чтобы мы могли просмотреть все статьи в нашем блоге, которые связаны с этим конкретным тегом.
(8:30)
Хорошо, давайте перейдём обратно в браузер:
laravel5.dev/articles/16
обновим и готово. Вот наши теги. Но как насчёт какой-нибудь другой статьи?
laravel5.dev/articles/4
У нас нет здесь никаких тегов, но мы всё ещё видим надпись. Может быть, это нормально, или может быть, вы хотите проверить здесь, если у нас есть какие-то теги, то мы скажем, если это не пусто, т.е. @unless наш список тегов пуст, то отобразить их:
@unless ($article->tags->isEmpty())
...
@endunless
Запомните, стоит думать об @unless как об эквиваленте IF NOT (если не).
(9:00)
Так что теперь, если я вернусь и обновлю, мы ничего не увидим. Но если у нас есть теги, то вы увидите их. ОК, это всё хорошо, но у нас всё ещё есть одна проблема. У нас есть форма create, но как насчёт нашей формы edit? Что ж, давайте посмотрим. К сожалению, у нас сразу возникла ошибка.
Так что, похоже, для того, чтобы эта форма заработала, она должна содержать список тегов.
(9:30)
В этом видео мы просто пойдём по пути дублирования кода. Но я хочу, чтобы вы подумали о том, как было бы здорово, если бы был способ связать переменные с любым видом, даже если бы это был partial, который мы хотим включить? На самом деле есть такой способ, но мы пока не будем его рассматривать. Так что давайте вернёмся к PHPArticlesController
и если мы пойдём к методу PHPcreate()
, мы захватили наши тэги. Так почему бы нам ещё раз просто не сделать то же самое временно вот здесь, в PHPеdit()
, и затем передаём дальше:
$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()
непосредственно на статье, чтобы получить выбранные значения. Но мы используем привязку модели к форме, так что было бы здорово, если бы мы могли сделать что-то вроде этого:
public function getTagsAttribute()
Мы могли бы использовать метод вроде PHPgetTagsAttribute()
, но это уже не будет работать, потому что если мы это перезапишем и вернём массив или что-то типа того, то каждый раз, когда мы попытаемся использовать PHP$article->tags()
в наших разных файлах, то он больше не будет работать, не так ли? Поскольку мы перезаписали его.
(11:30)
Тогда, возможно, мы могли бы использовать что-то вроде PHPgetTagListAttribute()
. Хорошо? И когда мы будем говорить tagList или tag_list, то этот метод будет срабатывать. Тогда мы могли бы:
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)
Автору спасибо конечно, но очень много воды как обычно.