{{Laracast Laravel 5 Fundamentals, 9, Basic Model/Controller/View Workflow, 22.01.2015, 15.05.2016, https://laracasts.com/series/laravel-5-fundamentals/episodes/9}} %%(hvlraw) %% (0:00) Теперь, когда мы создали класс %%Article%%, и мы немного понимаем как работает Eloquent, почему бы нам дальше не рассмотреть процесс создания контроллера, загрузку записей из БД и отображение их на странице через наш вид? Это стало бы хорошим, простым примером начального уровня. Как я понимаю, наш первый шаг - нужно создать контроллер и также необходимо зарегистрировать маршрут (route). Итак, если мы откроем %%(t)routes.php%% - я уже показывал вам тот самый способ регистрации маршрутов. (0:30) Укажите URI, имя контроллера, знак %%(t)@%%, и вызываемый метод. Однако, если хотите (и особенно это полезно для небольших, быстрых задач), то можно сказать: %% Route::get('foo', function() { return 'Bar'; }); %% Мы просто передали замыкание. Например, если я возвращаю %%'Bar'%%, то это сработает. И чтобы вам это доказать - мы откроем в браузере эту страницу: %%(t) laravel5.dev/foo %% (1:00) ...и точно, мы получили %%'Bar'%% в ответ. Это может быть очень удобно, особенно для написания штук типа API. Однако для обычных приложений я больше предпочитаю такой подход: %% Route::get('contact', 'PagesController@contact'); %% То есть когда пользователь делает GET-запрос к статьям, то мы хотим загрузить %%ArticlesController%%, а именно его метод %%index()%%: %% Route::get('articles', 'ArticlesController@index'); %% Отлично. Мы зарегистрировали маршрут, но у нас ещё не создан %%ArticlesController%%. Создадим его: %%(sh) php artisan make:controller ArticlesController --plain %% И снова применим здесь параметр %%(t)--plain%%. (1:30) Так, давайте проверим это и мы будем готовы начать. Мы вызовем метод %%index()%%, и посмотрим, сработает ли это. Как насчёт: %% public function index() { return 'get all articles'; } %% Отлично. Теперь назад в браузер и открываем: %%(t) laravel5.dev/articles %% Наш метод срабатывает. Классно. Следующий шаг... мы хотим загрузить все статьи, не так ли? И вы уже научились применять некоторые простые методы Eloquent на последнем уроке. (2:00) Так, давайте попробуем. Я хочу сделать так: %% $articles = Article::all(); %% Мы научились использовать %%Article::all()%%, но не забывайте что нам нужно ссылаться на всё пространство имён (%%\App\%%). Взамен, я просто импортирую класс в самом верху: %% use App\Article %% ОК, это довольно красивый способ, особенно для небольших CRUD-приложений. Замечательно! Не нужно здесь ничего менять. Теперь смотрите что случится, если мы просто вернём результаты этого вызова: %% return $articles; %% (2:30) Переключимся обратно в браузер, обновим страницу... Смотрите! Мы возвращаем JSON. Это одна из классных штук в Laravel - он достаточно умён чтобы знать, что если мы так используем %%return%%... Может быть мы строим простой API или нечто наподобие того, и в этом случае всё нужно приводить к формату JSON. И если вы хотите взглянуть на сырые выходные данные - то вот, что мы получим здесь. Классно? Всё это уже в комплекте. Но конечно же, в данном случае, мы хотим всё красиво оформить и вывести кое-какой HTML. (3:00) Так что нам нужен не JSON. Мы хотим загрузить вид (view). Возвращаем новый вид (%%(t)articles.index%%), используя соглашение о котором уже говорили, и, наконец, я хочу передать переменную %%(t)articles%%: %% return view('articles.index', compact('articles')); %% Так что запомните - мы можем прямо так и напечатать. Или если хотите больше наглядности, то можно так: %% return view('articles.index')->with('articles', $articles); %% Любой из подходов работает. В моём случае, для простых вещей, мне нравится подход с %%compact()%%. Но, вам решать, тут нет неверного решения. Дальше. (3:30) Я переключусь на %%(t)/resources/views%% - нам нужно создать папку для новых статей: %%(t) articles/index.blade.php %% Дальше, не забудьте, что у нас есть эта главная мастер-страница, и мы рассмотрели идею с файлом-макетом в одном из прошлых уроков. Нам лишь остаётся расширить его и создать раздел для нашего контента, а если нужно как-то изменить подвал (footer), то можем и это сделать. (4:00) %%(html) @extends('app') %% Далее для моего раздела (тут его содержимое): %%(html) @section('content'); %% Начнём с простого тега %%(t)

%%: %%(html)

Articles

%% Отлично. Давайте взглянем в браузере. Обновим страницу. И вот оно! У нас полноценный HTML, и мы вставили содержимое страницы прямо в тег-контейнер. Не забывайте, в нашем виде у нас есть доступ к переменной %%$articles%%. Так что мне всего лишь нужно перебрать статьи и отобразить каждую. (4:30) ОК, это довольно просто. Используем Blade: %%(html) @foreach ($articles as $article) %% и затем закроем: %%(html) @endforeach %% И для начала... почему бы не использовать тут элемент %%(t)
%%? Интересное совпадение ("article" - "статья"). Внутри %%(t)

%% выведем название статьи. И, наконец, раздел для тела документа - сделаем %%$article->body%%: %%(html)

{{ $article->title }}

{{ $article->body }}
%% (5:00) Отлично. Круто! Итак, если обновим страницу - у нас есть две страницы (в данном случае). Их мы создали в предыдущем уроке, когда баловались с Artisan. Итак, это было просто. Теперь, когда мы понимаем как отобразить все статьи, как насчёт простого формата блога, где можно просматривать каждую статью поодиночке? Как нам это сделать? Ладно. Мы хотим чтобы ссылки работали (как это типично для блогов). Так что мы обернём это в тег %%(t)%%. Также есть вспомогательная функция, которую я покажу вам чуть позже. Но пока используем обычный HTML. Так как нам установить там %%(t)href%%? (5:30) У нас ещё нет зарегистрированного маршрута, так что давайте разберёмся с этим. Сделаю-ка я копию. Что, если мы направим ссылку в %%(t)articles/%%, и потом добавим slug для статьи... Но у нас этого пока нет. Пока что воспользуемся id (%%(t)articles/{id}%%) Если мы хотим принимать запросы по маске пути, то вот какой формат здесь сработает. Даём имя, id, и заворачиваем в фигурные скобки. Это значит, что мы захватим всё из этой части URI. (6:00) Значит, если запрошен %%(t)articles/{foo}%%, то захватим ключ %%(t)foo%% и загрузим %%(t)ArticlesController@show%%: %% Route::get('articles/{id}', 'ArticlesController@show'); %% ОК. Давайте быстро настроим это, чтобы мне вам показать. У нас есть новый метод %%show()%%, который примет %%$id%%, и если мы его выберем и возвратим: %% public function show($id) { return $id; } %% (6:30) Заметьте, что за кулисами Laravel автоматически вызовет этот метод %%show()%% и передаст %%$id%%. Посмотрим на это в действии. Итак: %%(t) laravel5.dev/articles/foo %% И вот мы выбрали его. Заметьте, что нет никаких ограничений. Если мы передадим 1, то это всё равно сработает. И вы можете это поменять если захотите. Вы можете использовать только регулярные выражения, указывая, что конкретно должно совпасть. Но в нашем случае этот момент нас не заботит. Итак, теперь у нас есть возможность захватывать идентификатор статьи. (7:00) Здесь id статьи делает её уникальной. И если подумать, то это не очень хорошо. Мы не хотим использовать какой-то столбец в БД для представления статьи пользователю. Это не очень интуитивно понятно, не так ли? Не лучше ли сделать идентификатором какой-нибудь уникальный упрощённый заголовок статьи (slug) для связи со статьёй? Например, %%(t)my-first-article%%. Это было бы немного более уместным. (7:30) Но в этом случае, у нас нет этого, так что пока будем работать с id. Для нашей демо - это нормально. Так как же нам выбрать статью с конкретным id? В прошлом эпизоде мы об этом уже говорили, так что это должно быть лёгким заданием для вас. Воспользуемся %%Article::find()%% для предметов с id. И снова, чтобы показать вам, я верну статью, сконвертированную в JSON: %% public function show($id) { $article = Article::find($id); return $article; } %% Теперь выполним это: %%(t) laravel5.dev/articles/1 %% и готово! Вот она для id = 1. И вторая - она отличается: %%(t) laravel5.dev/articles/2 %% (8:00) Но что же делать если мы выберем id, который не существует, например 3? Заметьте, что мы ничего не видим, поскольку на выходе null. Если мы захотим вывести на экран данные, чтобы действительно в них покопаться, то можно применить функцию %%dd()%% ("покажи и умри" - "dump'n'die"). Заметьте, если я передам так: %% dd($article); %% и вернусь в браузер и обновлю страницу - мы действительно сможем увидеть с чем мы тут работаем. В этом случае - здесь просто null, но по другому пути мы можем залезть в объект %%Article%% и на самом деле увидеть, что здесь у нас. Это просто здорово! (8:30) Но теперь подумайте: если есть вероятность что код вернёт null, то, как вы можете себе представить, когда мы загрузим такой вид: %% return view('articles.show', compact('article')); %% ...мы передаём %%$article%% и ожидаем, что это объект со свойствами. Так? Мы надеемся сделать %%$article->title%%. Однако, %%$article%% равен null, следовательно, когда мы запустим это в нашем шаблоне, то, конечно, ничего не получится. Вы не можете читать свойства у null. (9:00) Похоже нам нужно выразить что-то вроде: "Если результат = null, то сделать перенаправление, или выбросить исключение, или остановиться. Что угодно." Вручную это делается так (хотя есть лучший способ для этого): %% if (is_null($article)) %% или можно просто сказать: %%if ( ! $article)%% (чтобы проверить на ложность). Но если получен null, то что-то не в порядке, так что давайте просто остановимся. И отобразим страницу 404: %% if (is_null($article)) { abort(404); } %% (9:30) Хорошо, давайте попробуем: %%(t) laravel5.dev/articles/5 %% Мы выдали пользователю страницу 404. И помните, сейчас мы можем увидеть детали исключения, но для производственной версии приложения (идём обратно в %%(t)config/app.php%% и листаем вверх) не забудьте установить %%'debug'%% в %%false%% в файле %%(t)production.env%%. Вот так это будет выглядеть в производственной версии. Если мы взглянем - вот то, что они увидят. И конечно вы можете править эту страницу ошибки как захотите. (10:00) Так, небольшая заметка здесь. Вернёмся назад... Нам не нужно делать этого, так как, если подумать, то нам почти каждый раз нужно иметь такую стандартную заготовку типа "если null, сделай то-то". Laravel нам здесь поможет. Я могу сказать %%findOrFail()%%, или другими словами, найди запись с таким id, а если не найдёшь, то заверши неуспехом: %% $article = Article::findOrFail($id); %% Идём обратно и обновляем страницу: %%(t) laravel5.dev/articles/5 %% и заметьте, что Laravel бросил специальное исключение %%ModelNotFoundException%%. (10:30) Так что мы позднее сможем поймать его в любом месте в нашем приложении и обработать по необходимости. Вот как это работает. ОК, но мы это рассмотрим ещё раз в будущем, так что не старайтесь всё это запоминать. Вместо этого продолжим и давайте создадим наш вид тут. У нас уже есть %%(t)index%%, теперь нам понадобится %%(t)show.blade.php%%. Давайте скопируем немного этого кода. (11:00) Так, но теперь вместо обработки всех статей, я хочу отобразить заголовок статьи %%(t){{$article->title}}%%, и нам не нужно проходить через них все, так что я могу сказать: %%(html) {{$article->body}} %% ОК, давайте посмотрим. Идём на: %%(t) laravel5.dev/articles/1 %% и вот он! %%(t) laravel5.dev/articles/2 %% и вот этот тоже! А если мы пойдём на: %%(t) laravel5.dev/articles/ %% то увидим весь список. Однако мы с ним ещё не разобрались и не выставили значение для %%(t)href%%. Сделаем это сейчас. Обратно к нашему виду. Как нам это сделать? (11:30) Я покажу вам пару способов. Первый - мы всегда можем просто вбить адрес напрямую: %%(html) {{ $article->title }} %% Это сработает. Вернёмся, обновим: %%(t) laravel5.dev/articles/# %% и если я посмотрю в исходный код - теперь у нас есть правильный %%(t)href%%. И если хотите убедиться - смотрите: вот один, и второй. Итак, очень простенький блог можно сделать всего за пару минут. Это совсем не сложно. Но пока переключимся обратно - есть ещё другие способы как это сделать. (12:00) Например, вы не хотите думать о URI, а хотите мыслить категориями методов у %%Controller()%%, которые вы хотите вызывать. Например, вы хотите сказать: "Я просто хочу ссылку на правильный URI, чтобы мы могли запустить метод %%show()%%". ОК, вот как это сделать. Laravel даёт нам хорошую вспомогательную функцию %%action()%%. Передаём ей имя, которым тут будет %%(t)ArticlesController@show%%. (12:30) Далее если нужно передать какие-то параметры, то даём их как массив %%[$article->id]%%. Так что это ещё один способ получения ссылки %%(html) {{ $article->title }} %% Попробуем. Обновим: %%(t) laravel5.dev/articles/1 %% и мы должны получить всё ту же штуку. И вот она. Напоследок, если вам не нравится этот подход, можно также использовать функцию %%url()%%, так мы можем написать: %%url('/articles')%%, и затем передать любые дополнительные части пути. В нашем случае - это идентификатор статьи: %%(html) {{ $article->title }} %% (13:00) Хорошо, давайте попробуем этот метод. Обновляем страницу, и если заглянем в исходный код, то увидим в точности то же самое. Значит это сработает так же хорошо. Итак, как видите, в действительности есть несколько разных способов справиться с этой задачей. И есть ещё некоторые вещи, которых мы даже не коснулись. Например, в будущем мы поговорим об идее именованных маршрутов, где вы присваиваете идентификатор (какое-то имя для заданного маршрута). Затем, если вы хотите на него сослаться, можете использовать функцию %%route()%%. (13:30) В этот раз мы говорим: "Иди по маршруту с именем (любое присвоенное, например) %%(t)article_path%%." Так что это тоже вариант. Но я не хочу вас загружать, так что придерживайтесь варианта с функцией %%url()%% или %%action()%%. Какой вам больше нравится? Хорошо, отличная работа! В этих видео вы уже узнали, как можно легко создавать контроллеры - фактически генерировать их. (14:00) Вы изучили как использовать шаблон ((ВП:Active Record==)), чтобы, по сути, легко ассоциировать объект со строкой в БД. И наконец, вы научились как, в пределах нашего контроллера, очень легко выбрать данные, загрузить вид и отобразить его. Это совсем не сложно.