{{Laracast Laravel 5 Fundamentals, 23, Syncing Tags, 9.02.2015, 18.07.2016, https://laracasts.com/series/laravel-5-fundamentals/episodes/23}} %%(hvlraw) %% (0:00) Если вы смотрели наш самый последний урок, то я там остановился на своего рода интриге. Например, у нас здесь есть 2 тега. Давайте представим, что %%(t)coding%% был добавлен по ошибке, на самом деле здесь нужен только %%(t)personal%%. Хорошо, я отредактирую статью, или удалю один тег, и, если я обновлю страницу, блин, он всё ещё здесь. И мы можем в этом убедиться – сделаю запрос в SQLite: %%(sql) select * from articles; %% и эта статья имеет идентификатор 16, так что: %%(sql) select * from article_tags where article_id = 16; %% (0:30) и да, в БД у нас всё ещё есть 2 тега. Так в чём же здесь проблема? И если вы задумаетесь, то это довольно очевидно. Я вернусь к моему %%ArticlesController%%, где мы обновляем существующую статью вот здесь, в %%update()%%. Заметьте, что в этом случае мы обновили модель %%Article%% и таблицу статей, но мы не обратили никакого внимания на саму сводную таблицу. (1:00) И на самом деле это всего лишь первый шаг для решения этой задачи, но давайте сделаем его в самую первую очередь. Итак, давайте посмотрим, если я перейду в мой метод %%store()%%, вот тот раздел что мне нужен. Если помните, мы берём статью, существующую статью, находим связанные с ней теги, а затем с помощью %%attach()%% добавляем новый тег в эту сводную таблицу. Что если я возьму вот это и просто скопирую и вставлю сюда, будет ли это работать? Подумайте об этом минутку. (1:30) И давайте проверим это в браузере. Я отредактирую это ещё раз, мы удаляем %%(t)coding%%, я обновлю статью и давайте посмотрим. Блин, всё стало ещё хуже. Раньше у нас были %%(t)personal%% и %%(t)coding%%, но теперь у нас на самом деле появилась ещё одна ссылка на тег. Давайте проверим. Выполним наш запрос ещё раз, и да заметьте, мы добавили это дважды. Очевидно, что мы не хотим так делать. (2:00) И у нас на самом деле есть пара способов решить эту проблему. Во-первых, можно было бы с помощью SQL убедиться, что такая пара всегда уникальна. И таким образом он по определению не позволит вам создать новую запись где %%(t)article_id%% = 16 и %%(t)tag_id%% = 1. Это один вариант, но в нашем случае я хочу решить эту проблему по-другому. Как бы нам по сути синхронизировать всё так, чтобы я мог сказать: "всегда при запуске этого метода просто убедитесь, что этот массив идентификаторов тегов, что я даю вам, единственный, который существует в сводной таблице для этой модели"? (2:30) Я надеюсь вы понимаете о чём я. И как выясняется, термин %%(t)sync%% (синхронизация) и на самом деле является здесь ключевым словом, так что на этот раз я сделаю только одно изменение вот здесь. Вместо метода %%attach()%%, и кстати, есть также метод %%detach()%%, который выполняет противоположную функцию. Но у нас также есть метод который называется %%sync()%%. (3:00) Он так же принимает массив идентификаторов, однако ключевая вещь для понимания в том, что этот массив идентификаторов тегов будет единственным в базе данных, связанным с этим конкретным идентификатором статьи. И это означает, что Laravel будет сам заботиться об удалении и добавлении. Насколько это круто, а? Почему бы нам это не попробовать? Но для начала давайте здесь немного подчистим. Давайте исправим нашу раннюю ошибку. Почему бы нам просто не сделать: %%(sql) delete from article_tag; %% опустошим эту таблицу. (3:30) Хорошо, вернёмся в Chrome. Мы находимся на странице редактирования %%(t)edit%%. Я добавлю %%(t)personal%% и %%(t)coding%%, как мы делали раньше, обновлю, теперь посмотрим, и готово. Но теперь мы сделаем новое изменение. И в этот раз, как и в начале видео, я удалю %%(t)coding%%, и если я обновлю статью, смотрите, на этот раз всё работает. Так что давайте разберёмся. Запустим снова, и на этот раз, так как нам и было нужно, вторая запись в этой таблице, связывавшая статью с тегом %%(t)coding%%, теперь удалена. (4:00) И это именно потому, что мы здесь использовали метод %%sync()%%. Так что просто помните: %%attach()%% когда вы хотите добавить новые строки в сводную таблицу, %%detach()%% когда вы хотите удалить их, и %%sync()%% когда вы хотите всё синхронизировать. Мы предоставляем массив из идентификаторов тегов, в этом случае, и только эти идентификаторы будут ассоциироваться со статьёй в сводной таблице, всё остальное в таблице будет удалено. (4:30) Так почему бы нам не сделать вот что, почему бы нам не извлечь этот private-метод в нашем контроллере и не назвать его %%syncTags()%%? И если мы запустим это, мы, вероятно, немного подправим его. Я не хочу передавать запрос на всю статью. Давайте изменим это и лучше будем передавать статью и список тегов, вот так: %% $this->syncTags($article, $request->input('tag_list')); %% ОК, так что: %% private function syncTags(Article $article, array $tags) { $article->tags()->sync($tags); } %% (5:00) %%(t) * Синхронизировать список тегов в базе данных. %% Теперь мы можем использовать этот же метод в нашем методе %%store()%%, где мы создаём статью. Вот здесь: %% $this->syncTags($article, $request->input('tag_list')); %% мы передаём %%$article%% и снова %%(t)tag_list%%. И, наконец, почему бы нам не выделить это в метод, ведь по сути мы здесь именно это и делаем. Мы создаём новую статью или публикуем статью, или как вам удобнее это представлять. Давайте сделаем всё просто и скажем: %% this->createArticle($request); %% (5:30) ОК, я добавлю этот метод и вставлю это сюда. Тогда я смогу сделать: %% return $article; %% в нижней части, и затем давайте введём вот это (%%ArticleRequest $request%%) и создадим docblock: %%(t) * Сохранить новую статью. %% И, наконец, здесь: %%(t) * Создать новый экземпляр контроллера статьи. %% Хорошо. Хорошо, давайте рассмотрим этот контроллер, по-прежнему очень чистый. (6:00) У нас есть метод %%index()%%, где мы извлекаем последние опубликованные статьи и загружаем вид. Отлично. У нас есть метод %%show()%% чтобы показать статью, в котором мы просто используем привязку модели к маршруту, чтобы получить статью, и затем загружаем вид и передаём его дальше. Далее у нас имеется страница %%create()%% для создания статьи. Мы выбираем некоторые теги из выпадающего списка и загружаем вид. Далее сам процесс сохранения новой статьи – мы делаем автоматическую проверку данных в форме. (6:30) И затем, если всё соответствует требованиям, то мы создаём статью, выдаём flash-сообщение и перенаправляем пользователя. Обратите внимание как легко это читается. Здесь нет никаких строк, где вы должны думать 5 секунд и стараться выяснить что именно здесь происходит. Всякий раз, когда вы так делаете, стоит извлекать код в легко-читаемый метод. Это всё что мне нужно знать, мы создаём статью, и затем позже, если вы на самом деле захотите снова рассмотреть этот процесс, то вы можете копнуть глубже, но в общем, это всё, что нам тут нужно. Мы создаём статью. (7:00) Далее у нас есть страница для её редактирования %%edit()%%, где мы снова извлекаем теги и загружаем вид. Краткое замечание, обратите внимание, как мы продублировали это здесь. Я поднял эту тему в последнем видео. Думайте об этом, есть ли способ, чтобы автоматически привязать список тегов для этой формы? Мы вернёмся к этому позже. Далее мы обновляем статью в %%update()%%. Снова мы проводим проверку, используя тот же класс формы запроса, а затем мы обновляем статью, синхронизируем теги и переадресуем назад к списку статей. (7:30) И, наконец, так как наш проект всё ещё довольно мал, это нормально, что у нас здесь есть такие вещи. Вы не умрёте от того, что у вас есть private-метод в вашем контроллере. Так, у нас есть здесь один для синхронизации наших тегов, и ещё один, который дирижирует процессом создания и сохранения новой статьи. Хорошо, вполне достаточно для этого урока. Вы узнали как синхронизировать ваши сводные таблицы, а также как делать небольшой рефакторинг.