{{Laracast Laravel 5 Fundamentals, 17, Midterm Review, 2.02.2015, 11.07.2016, https://laracasts.com/series/laravel-5-fundamentals/episodes/17}} %%(hvlraw) %% (0:00) Хорошо, в этом уроке мы резюмируем изученное в первой половине серии. Так что мы не будем давать новую информацию. Мы просто рассмотрим всё то, что мы изучали до сих пор, и убедимся, что всё останется свежим в вашей памяти. И это означает, что если у вас уже есть очень хорошее понимание всего материала, что мы с вами прошли, то вы можете пропустить это видео и перейти к следующему, где мы поговорим о привязке модели к маршруту. Хорошо, давайте взглянем на наш прогресс. Пока что, с точки зрения веб-браузера, может показаться, что мы не так уж много и сделали, но если задуматься, то мы достигли приличного результата. (0:30) Давайте начнём с %%Article%%, нашей модели Eloquent для статей. Хорошо, мы начинаем, устанавливая свойство %%$fillable%%, которое защищает нас от массового назначения, чтобы плохие люди не могли по-хитрому изменить поля формы, дабы попытаться обновить записи, которые мы не хотим. Вместо этого мы явно задаём, какие поля могут быть массово назначены, когда вы делаете такие вещи, как: %% Article::create($array) %% (1:00) Это означает, что, например, если в таблице есть какой-то %%(t)permission_id%%, и вы не хотите давать пользователю доступ к ней... Если он включён здесь, то они смогут сделать это. Но поскольку его там нет, то даже если они пытаются включить %%(t)permission_id%% в пределах массива, который вы только что передали в %%Article::create()%%, так как его нет в этом списке, то мы это просто будем игнорировать. Так что это очень хорошая вещь. OK, дальше, мы использовали поле %%$dates%% так, чтобы мы могли добавлять дополнительные столбцы, которые будут обрабатываться как экземпляры Carbon. (1:30) В нашем случае, мы добавили %%(t)published_at%% для определения, когда статья будет опубликована. И когда мы извлекаем это, мы хотим взаимодействовать с ним, как с экземпляром Carbon, так что мы сможем делать, например, так: %% $article->published_at->format('Y-m'); %% Может быть мы отформатируем дату как год и месяц. И поскольку это экземпляр Carbon, то %%$published_at%% будет объектом, а не просто строкой. И, конечно же, не забывайте, что по умолчанию, %%$created_at%% и %%$updated_at%% будет одним и тем же. (2:00) ОК, дальше мы говорили об областях запросов. И думайте о них как о способе для нас, чтобы присваивать имена каким-нибудь условиям типа %%(t)where%%. В нашем случае, если мы часто хотим выбирать статьи, для которых %%$published_at%% равно сейчас или в прошлом, по сути исключая всё, что будет опубликовано в будущем, то вы могли бы повторять это каждый раз, но зачем вам это делать? Вместо этого добавьте область следуя конвенции где вы пишете %%(t)scope%%, затем имя, которое вы хотите использовать. (2:30) А затем он будет принимать запрос, в котором условие будет выполняться только один раз. Теперь мы можем сделать например, так: %% Article::published() %% Что будет вызывать этот метод. И, кстати, если вы хотите передать какое-то значение %%$value%%, которое должно быть использовано, то просто сделайте это таким образом, и оно будет приниматься как второй параметр. ОК, так что это были области запросов. Давайте продолжим. Далее, мы узнали о мутаторах и accessors следующих этой схеме. (3:00) Если, когда мы устанавливаем какое-то свойство, мы хотим чтобы за кадром Laravel что-то сделал, то мы можем использовать эту конвенцию – слово %%(t)set%%, затем имя свойства, и затем, наконец, слово %%(t)Attribute%%. Вы увидите это довольно часто, если я перейду к моей модели пользователя %%User%%, с таким примером. Мы могли бы добавить: %% setPasswordAttribute($password) %% И это будет принимать пароль. И затем, может быть, вы могли бы сказать: %% $this->attributes['password'] = mcrypt($password); %% Пароль этого атрибута будет равен хэшированной версии. (3:30) И в принципе, это позволяет нам делать такие вещи: %% $user->password = 'foobar'; %% Но на самом деле, когда мы сохраним его, то %%(t)foobar%% будет захэширован. Таким образом, мы вызываем это свойство, Laravel понимает, что устанавливается мутатор, затем вызывает метод, передаёт %%(t)foobar%%, а затем мы обновляем список атрибутов или массив, и делаем это равным зашифрованной версии %%(t)foobar%%. На самом деле полезно, и ещё раз, это удерживает нас от того, чтобы делать всё это снова и снова. Просто нужно объявить это один раз. (4:00) ОК, далее мы узнали об отношениях. Если статья написана пользователем, то само собой разумеется, что, когда у вас есть объект статьи, вы хотите выбрать пользователя, связанного с этой статьей. Мы можем сделать это так. Теперь, когда мы говорим: %% $article->user %% это даст нам объект пользователя, создавшего данную статью. И опять же, в основном, это будет проверять, чему равен %%(t)user_id%% для этой статьи. А затем найдёт пользователя, с таким идентификатором в базе данных. (4:30) И, конечно, обратное тоже верно. И, кстати, мы можем удалить вот это из предыдущего урока. Если статья принадлежит пользователю, то пользователь пишет статью. Так что, если пользователь может написать много статей, то мы используем отношение %%hasMany()%%. Пользователь не принадлежит статье, поэтому мы не делаем это. И у пользователя нет ровно одной статьи, поэтому мы не делаем и этого. У пользователя есть много статей. ОК, так что если мы переключимся назад, это были наши модели Eloquent. Мы достаточно много изучили в этой области. (5:00) Далее, почему бы нам не перейти к нашим контроллерам. Если мы посмотрим на %%ArticlesController%%, первое, что мы увидим, то что мы тут добавили посредников. И это ещё одна вещь, которую вы узнали в самом последнем уроке. Посредник – как слой луковицы, так что он даёт нам возможность создавать любое количество классов, которые будут получать запрос и либо передать его дальше по цепочке, если нет никаких проблем, либо он может даже отклонить запрос и отправить пользователя ещё куда-нибудь. (5:30) В этом случае, если мы хотим защитить страницу от любых аутентифицированных пользователей, например для страниц, которые должен увидеть только гость на вашем сайте, то вы могли бы добавить посредника. "Пожалуйста, проверьте, если у нас пользователь аутентифицированный, и если это так, то перенаправьте его на главную страницу. Если он уже вошёл в систему, то просто отправим его к dashboard". Хорошо, давайте переключимся обратно. Дальше мы узнали, что контроллер в основном отвечает за получение разных запросов, делегирование их по мере необходимости, для исполнения запроса, а затем за возврат ответа. (6:00) Так что, как вы обнаружите, большинство из этих методов контроллера, всего одна, две, может быть три строки кода длиной. И на самом деле, уже в следующем уроке я покажу вам, как вы сможете это ещё сильнее уменьшить. Но я не хочу опережать события. Итак, если мы прокрутим файл вверх, то вот где мы можем ссылаться на наши отношения. Если мы хотим допустим получить аутентифицированного пользователя и сохранить новую статью: %% Auth::user()->articles()->save($article); %% Обычно, чтобы создать статью, вам нужно будет ссылаться на %%(t)user_id%%. (6:30) Но если мы используем отношения Eloquent, то это может быть сделано за нас автоматически. Просто зайдём через пользователя, в котором мы заинтересованы. Так что, %%(t)user%%, получим все его статьи и сохраним новую. %% Auth::user()->articles()->save($article); %% И делая это так, %%(t)user_id%% будет добавлен автоматически. Далее мы узнали о формах запроса, так чтобы мы могли автоматически проверять данные в форме. В этом случае, мы делаем подсказку типа %%ArticleRequest%%, что означает, что прежде чем этот метод сработает, мы проверим запрос, или данные формы, на соответствие этому набору данных. (7:00) Теперь, если это не сработает, то мы перенаправимся назад и покажем список ошибок, которые пользователь может исправить в форме и повторить попытку. А если проверка проходит, только при этом условии мы вызовем содержимое этого метода с пониманием того, что у нас данные в нужном формате. Тем не менее, мы также говорили о том, что если вы не хотите создавать запрос формы и на самом деле, вы просто хотите убедиться, что некоторое поле присутствует, одно или два, то вы могли бы вызвать метод %%validate()%% непосредственно в самом контроллере. (7:30) Так что проверим запрос на соответствие некоторому набору данных: %% $this->validate($request, ['title' =>'required']); %% Это очень полезно для мелких и базовых вещей, которые на самом деле не оправдывают создание специального класса. Хорошо, но я приведу тут код обратно к тому, что у нас здесь был ранее. Дальше, если мы перейдём на %%(t)routes.php%%, мы узнали, что Laravel, по умолчанию, включает в себя некоторые возможности аутентификации, и есть даже некоторые вещи, о которых мы ещё не говорили. Например, сброс паролей. Всё это также включено. (8:00) Однако мы вернёмся к этой теме позже. Главное что %%AuthController%% и %%PasswordController%% есть по умолчанию. Так что если вы хотите, вы можете воссоздать их по своему усмотрению, но на самом деле для этого нет необходимости. Теперь мы можем настроить и начать работать с системой пользователей, может быть, за несколько минут. Хорошо, что ещё? Ну, конечно же, вы узнали как использовать Blade и как экранировать или не экранировать данные. Blade - отличный движок для шаблонов. Он мне очень нравится. (8:30) Далее, вы узнали об окружении и конфигурации. Мы создаём файл %%(t).env%% для каждого окружения, и это определяет, какие параметры и значения мы хотим использовать. Например, если мы идём в %%(t)config/app%%, обратите внимание, что наш режим %%(t)debug%% установлен в %%(t)true%% (в нашей локальной среде). Это имеет смысл, не так ли? Когда мы работаем локально, если что-то пойдёт не так, мы хотим видеть комплексный протокол для отладки. Но, конечно же, для производства, вы не хотите, чтобы это произошло. (9:00) Это очень опасно. Вместо этого, вы просто хотите отобразить простенькую страницу типа "Ой! К сожалению, что-то пошло не так, пожалуйста, повторите попытку позже". Мы никогда не станем показывать пользователю закрытые данные нашего сервера. Поэтому, как только вы внедрите приложение, вы создадите ещё один файл %%(t).env%% в вашей производственной версии. Так что это важная вещь для понимания. Именно этот файл никогда не будет существовать на производственном сервере. И на самом деле, если вы используете Git, и я надеюсь, что вы это делаете, а если нет, то это нормально, просто начните изучать его в ближайшем будущем. (9:30) В любом случае, вы увидите, что этот файл включен в файл %%(t).gitignore%%, так что мы не храним его в контроле версий. И таким образом, мы не загрязним его всеми этими паролями, которые мы не хотим туда включать. Итак, ещё раз, на производственном сервере, создайте этот файл и воспроизведите эти параметры, но затем обновите значения. Таким образом, для производства, %%(t)APP_DEBUG%% должен быть установлен в %%(t)false%%. Так это работает. (10:00) А потом, в ваших различных конфигурационных файлах, мы схватим эти значения там, где нам нужно. Или вы даже можете установить значения по умолчанию. Так %%(t)APP_DEBUG%%, сделайте по умолчанию равным %%(t)false%% или %%true%%. Как вам угодно. %% 'debug' => env('APP_DEBUG', false) %% Далее, давайте рассмотрим ещё пару вещей. Вы узнали о миграциях базы данных. Так что, если мы проверим наши различные миграции, вот одна для создания таблицы статей. Это даёт нам невероятно простой способ определения схемы для наших таблиц базы данных. (10:30) И даже лучше, они хранятся в системе контроля версий. А это значит, что вы можете отправить этот проект любому человеку на другой стороне земного шара, и всё что ему потребуется сделать, это запустить: %% php artisan migrate %% чтобы создать точно такую же конфигурацию БД как и у вас. Так что в этом случае, мы хотим, чтобы первичный ключ был %%(t)id%% и со свойством autoincrementing (%%increments()%%): $table->increments('id') Нам нужен %%(t)user_id%%, но также этот пользовательский ключ является внешним ключом (foreign key), так что мы хотим сказать: "Он ссылается на поле %%(t)id%% в таблице пользователей". (11:00) И если нам придётся удалить пользователя, то давайте пойдём каскадом вниз и удалим также статьи пользователя. Просто убедитесь, что это логика которую вы хотите. Вполне может быть, что вы не захотите делать этого, и вы просто решите мягко удалить его и просто отключить статьи. Но это немного более сложный уровень, чем тот, где мы сейчас находимся. И далее у нас есть миграции для случаев, когда нам нужно изменить что-то после того, как мы уже сделали внедрение. (11:30) Ну что же, создадим миграцию, в этом случае, для добавления поля для выдержек %%(t)excerpt%% к таблице статей, и всегда помните, что указывать в обратном случае. Так что если мне когда-нибудь понадобится откатить эту миграцию, что ещё нужно будет здесь с этим делать? В этом случае мы просто удалим столбец. И, наконец, давайте взглянем на %%(t)articles/create%%. Мы узнали о том, как немного подчистить наши представления, так чтобы нам не пришлось повторяться снова и снова для обычных вещей типа форм или заголовков. (12:00) Так что вы узнали, что мы могли бы создать главную страницу (master page): %%(t) app.blade.php %% Вот так. И каждое представление что у нас есть будет наследовать от него или расширять его. И таким способом, нам не придётся копировать и вставлять такой код в каждое отдельное представление, это плохая идея. Но далее, мы узнали о таких вещах, как, если нам нужно одну и ту же форму для создания и обновления, то мы не хотим заново воспроизводить эту форму или копировать и вставлять её, потому что если бы мы так делали, то каждый раз, как нужно сделать какие-то изменения, вам бы пришлось обновлять форму в нескольких местах. (12:30) Мы не хотим так делать. Так что вместо этого, мы выделим её в нечто, что мы называем partial. Что-то вроде этого. И потом, в пределах каждого представления, вы можете включать этот partial, и, если вам нужно, то передавать любые параметры, чтобы отменить некоторые значения по умолчанию. Обратите внимание, что мы сделали то же самое для списка ошибок. Я, вероятно, захочу отобразить список ошибок в нескольких частях моего приложения для нескольких форм. (13:00) Так что я не хочу воспроизводить всё это, а вместо этого, вынесу его в partial, и затем включу его везде где мне нужно. ОК, хорошая работа. Думайте об этом видео, как о нашем обзоре в середине семестра, чтобы убедиться, что мы всё наверстали. Теперь, уже в следующем уроке, давайте продолжим изучать новый материал, и мы поговорим о привязке модели к маршруту.