{{Laracast Laravel 5 Fundamentals, 8, Eloquent 101, 21.01.2015, 25.05.2016, https://laracasts.com/series/laravel-5-fundamentals/episodes/8}} %%(hvlraw) %% (0:00) Сейчас, когда мы уже немного разобрались с миграциями, можем переключиться и поговорить о том как реализована в Laravel работа с Active Record (шаблон проектирования "Активная запись"). Я думаю вам это понравится. Итак, если я перейду в терминал и выполню: %%(sh) php artisan %% Вы увидите, что прямо здесь же у нас есть несколько генераторов файлов. Вот тот что нам нужен - %%(t)make:model%% – для создания класса модели Eloquent. Чтобы лучше понять, думайте, что когда вы используете Active Record, у вас будет один класс, который будет представлять одну строку в связанной таблице БД. (0:30) Так, если у меня есть таблица %%(t)articles%%, то моя модель Eloquent может быть названа %%Article%%. Для таблицы %%(t)users%%, имя модели Eloquent может быть %%User%%. И т.д. и т.п. Давайте посмотрим как это может выглядеть: %%(sh) php artisan make:model Article %% Хорошо, давайте взглянем. Если я открою боковую панель, мы увидим новую поддиректорию у директории %%(t)/app%%. (1:00) Если мы её откроем, то вот что получим – стандартный шаблон, чтобы нам было с чего начать. Важно заметить что наш класс расширяет эту родительскую модель. И это достаточно сложный класс, так что не думайте, что вы сразу должны со всем тут разобраться. В частности, тут есть такие штуки как %%save()%%. Таким образом, мы можем получить запись из БД, легко изменить её, и затем вызвать метод типа %%save()%%, чтобы сохранить изменения. (1:30) И, конечно, тут также есть %%update()%%, %%find()%% и некоторые другие методы, которые будут вам чрезвычайно полезны. Теперь, когда у нас есть наша модель, как нам тут немного с ней поиграть? Для этого мы можем использовать ещё одну команду Artisan под названием %%(t)tinker%%. Если я запущу: %%(sh) php artisan tinker %% У меня появится приятный и полезный интерфейс командной строки для работы с кодом Laravel. (2:00) И он отлично подойдёт для проверки функций и для выполнения PHP в целом. Всё это будет нам доступно. Зная это, давайте теперь поманипулируем с нашим только что созданным Eloquent - классом %%Article%%. Для начала просто создадим его: %% $article = new App\Article; %% И готово, у нас есть новый объект %%$article%%. Но теперь мы хотим заполнить его атрибутами, так? И если я вернусь обратно... (2:30) Напомню – когда мы создавали таблицу %%(t)articles%%, мы обозначили что нам требуются заголовок %%(t)title%%, тело %%(t)body%%, временные штампы %%timestamps()%%, а также дата публикации %%(t)published_at%%. Так почему бы не начать с добавления их всех? И у Eloquent есть простой и приятный способ для этого. Почти как доступ к обычному полю: %% $article->title = 'My First Article'; %% Далее, добавим тело статьи. Просто напишем здесь %%(t)Lorem ipsum%%. (3:00) Тут есть одна крутая штука – временные штампы (timestamps) будут добавлены автоматически. Вам не нужно делать это вручную. Они будут установлены на текущее время, но для поля %%(t)published_at%% давайте установим его явным образом: %% $article->published_at = Carbon\Carbon::now(); %% (как насчёт текущего времени?) Для этого мы можем использовать популярную библиотеку Carbon, которую Laravel подтягивает по умолчанию. Так что мы используем %%Carbon%% и пишем %%now()%% – текущее время. И готово. На момент этой записи – это 21 января. (3:30) Итак, мы заполнили наш объект %%$article%%. Можем просмотреть его так. Или даже проверить его атрибуты при помощи методов, типа %%toArray()%%. Итак, мы создали объект, но ещё не сохранили в БД. Это следующий шаг. И вы уже знакомы с методом %%save()%%: %% $article->save(); %% В ответ получаем %%true%%, что означает, что мы успешно его обновили. Посмотрим, сработало ли это? Вот два способа для проверки. (4:00) Для начала перейдём прямо в нашу БД: %%(sh) sqlite3 storage/database.sqlite %% И теперь если я сделаю: %%(sql) select * from articles; %% Мы увидим эту запись. Очень просто! Или вернусь в %%(t)tinker%%: %%(sh) php artisan tinker %% Мы всегда можем сделать запрос здесь: %% App\Article::all()->toArray(); %% Получим все данные из таблицы и приведём к массиву чтобы было их проще посмотреть. И вот, пожалуйста. Получили одну запись. (4:30) Хорошо, мы уже сохранили статью в БД. Не забывайте, у нас есть доступ к той переменной. Почему бы нам теперь не обновить что-нибудь? И вы увидите насколько это просто. У нас уже есть наш объект, давайте скажем: %% $article->title = 'My updated First Article'; %% Отлично, мы обновили этот атрибут. Снова сохраним его: %% $article->save(); %% И сейчас ещё раз если мы сделаем тот же запрос, то вы увидите, что произошли изменения. Теперь, как насчёт обыденных и частых действий, которые вы будете часто выполнять? (5:00) Например, это: %%(sql) select * from table where id = 1; %% (id записи равен тому, что мы передаём). ОК? Мы все очень часто писали подобное, не так ли? А это будет выглядеть с Eloquent? Давайте попробуем: %% $article = App\Article::find(1) %% Передаём id, в нашем случае это 1. Теперь мы получили только одну запись из таблицы. Снова приведём его к массиву: %% $article->toArray(); %% (5:30) У нас есть наши данные, значит мы можем выдать их на экран как нам угодно: %% $article->title; %% Но как насчёт других операций? Например: %%(sql) select * from articles where body = 'Lorem ipsum'; %% Мы хотим найти любые статьи с этим конкретным телом %%(t)body%%. Как воспроизвести это в Eloquent? Например мы можем сказать: %% $article = App\Article::where('body', 'Lorem ipsum')->get(); %% (6:00) В этот раз добавим условие %%(t)WHERE%% - тело равно %%(t)Lorem ipsum%%. Отлично, мы добавили наше условие. Теперь я хочу получить результат. В нашем случае я получу на выходе коллекцию. Заметьте – %%Illuminate\Database\Eloquent\Collection%%. Вы узнаете чуть больше о коллекциях Laravel в скором будущем. Думайте о них как о "массивах на стероидах". Они предоставляют много гибкости для фильтрации, преобразования, добавления элементов и т.п. (6:30) Но не беспокойтесь, мы доберёмся до этого. Однако сейчас, в этом случае, что если мы хотим сказать: "Дай мне самую первую запись, которая соответствует нашему условию %%(t)WHERE%%". ОК, нам нужно лишь поменять одно слово. Вместо получения коллекции через %%get()%%, я использую %%first()%% чтобы взять только самый первый результат. И в этот раз результат изменился. Это просто обычный класс %%Article%%. И снова мы можем сказать: %% $article->body; %% для отображения значений. (7:00) Хорошо, идём дальше. Мы ознакомились с тем, что я бы назвал "медленным" способом. Где мы говорим: %% $article = new App\Article; %% И затем заполняем атрибуты один за одним. Что если вместо этого мы хотим сделать это одним вызовом? Как это будет выглядеть? Позвольте, я вам покажу. В этот раз мы скажем: %% $article = App\Article::create()... %% И разница здесь в том, что мы передадим массив значений. (7:30) Например: %%(t)title%% будет %%(t)New Article%%, %%(t)body%% равно %%(t)New body%%, и, наконец, %%(t)published_at%% сделаем равным %%Carbon\Carbon::now()%%. Закроем скобки и запустим: %% $article = App\Article::create(['title' => 'New Article', 'body' => 'New body', 'published_at' => Carbon\Carbon::now()]); %% Однако, гм... Ой, что тут произошло? Мы получили %%MassAssignmentException%%. Здесь Laravel на самом деле защищает нас. Мы много говорим об этом на нашем сайте. Если вы хотите отдельный урок на эту тему, то поищите "mass assignment" (массовое присваивание) на Laracasts.com. (8:00) Но, чтобы дать вам общее представление: когда мы передаём массив атрибутов методу типа %%create()%%, то мы массово присваиваем их. Так сказать, //en masse// (скопом). И когда вы так делаете, нужно быть предельно осторожными, чтобы конечный пользователь, или другими словами, человек, заполняющий форму, не смог попытаться скрытно манипулировать вами, или использовать ваш код, или изменить ожидаемые данные. Ведь значения в массиве, который передан в %%create()%%, к примеру, может "случайно" сменить права владельца записи с вас на злоумышленника. (8:30) Или, как ещё один пример, отредактировать свой аккаунт так, что он больше не пользователь, а администратор. Если не следить за этим, и не защищать своё приложение от таких вещей, пользователи взломают вас. И помните, если вы не выводите поле ввода в форме, то это не означает, что они не могут отредактировать форму, поменять имя поля, добавить новое поле, сделать что угодно и потом отправить эту форму вам. (9:30) И если вы просто берёте эту заполненную форму и направляете в метод типа %%create()%%, то... теперь вы видите к чему это может привести. Поэтому мы хотим обезопасить себя от таких случаев. И, к счастью, Laravel по умолчанию достаточно умён, чтобы делать это за нас. Если попытаться сделать нечто подобное без явного определения атрибутов для возможного массового присваивания, то Laravel рассердится и выдаст %%MassAssignmentException%%. И это очень хорошо. Давайте поправим наш код. Перейдём обратно и вернёмся в нашу модель Article. Сейчас я создам здесь поле: %% protected $fillable = [...]; %% Это поля для массового заполнения для модели статьи (%%Article%%). Другими словами, те атрибуты, что мы позволяем массово присваивать. Например, %%(t)id%% - вы хотите чтобы кто угодно мог менять ID записей? Нет, значит вы не будете включать его в этот список. То же насчёт, например, %%(t)user_id%%. Если вы не хотите, чтобы кто-то мог их менять, то убедитесь, что это поле не указано в данном массиве. (10:00) Итак, в нашем случае, мы согласны включить сюда %%(t)title%%, %%(t)body%%, и, возможно, %%(t)published_at%%. Это всё, что мы разрешаем для массового присвоения. И теперь, если конечный пользователь – человек заполняющий форму – попытается по-хитрому изменить ввод и изменить что-то иное, то мы это просто проигнорируем. Если поле не включено в данный массив, то мы просто отбросим лишнее. Так мы улучшаем безопасность нашего приложения. (10:30) Хорошо, мы обновили код, попробуем ещё раз: %%(sh) php artisan tinker %% Теперь я нажму клавишу "вверх", чтобы вернуть предыдущую команду. И в этот раз мы запускаем и всё работает: %% $article = App\Article::create(['title' => 'New Article', 'body' => 'New body', 'published_at' => Carbon\Carbon::now()]); %% Разница в этом подходе в том, что когда мы вызываем %%create()%%, все атрибуты заполняются и модель сохраняется в рамках этого вызова. Т.е. не нужно дополнительно вызывать %%save()%%. Попробуем: %% App\Article::all()->toArray(); %% (11:00) Получаем все статьи и приводим к массиву. Теперь у нас тут две записи. Теперь чтобы закончить тут, давайте найдём запись с %%(t)id%% равным 2, изменим тело статьи и сохраним запись. OK, я покажу вам два способа, как с этим справиться. Мы скажем: %% $article = App\Article::find(2); %% (Найдём запись, %%(t)id%% которой равен 2). %% $article->toArray(); %% Хорошо, это вы уже усвоили. Я надеюсь что вы работаете вместе со мной, поскольку это – лучший способ для фиксации новой информации в мозгу печатая её вручную самому. (11:30) Итак, у нас есть наша статья. Поправим её таким образом: %% $article->body = 'Updated'; %% И сохраним: %% $article->save(); %% Так она сохранится в БД. Теперь снова приведём к массиву, и всё работает: %% $article->toArray(); %% Второй метод как это сделать – это вызвать метод %%update()%%. Это похоже на работу с методом %%create()%%. Я вызову %%update()%%, передам массив атрибутов для изменения. (12:00) В нашем случае, например поменяем тело %%(t)body%% на %%(t)Updated AGAIN%%: %% $article->update(['body' => 'Updated AGAIN']); %% И теперь всё сделано. Вот что я имел в виду, когда говорил, что это схоже с методом %%create()%%. Мы вызываем %%update()%%, он заполняет объект новыми атрибутами и затем сохраняет сам себя. Теперь, если мы ещё раз вызовем метод и приведём к массиву: %% App\Article::all()->toArray(); %% Вы видите, что %%(t)body%% и правда изменилось. Хорошо, я думаю этого достаточно для этого урока, "Eloquent 101". Ещё можно много чего осветить, но для начала вам этого хватит. (12:30) В качестве домашней работы, я хочу чтобы вы позанимались с этим и хорошо освоились. Создайте миграцию и добавьте какую-нибудь учебную таблицу. Может быть для заданий (%%(t)tasks%%). Так, вы создадите миграцию , таблицу %%(t)tasks%%, откроете файл, настроите поля, и затем мигрируете вашу БД и создадите вашу модель: %%(sh) php artisan make:model Task %% И дальше воспользуетесь: %%(sh) php artisan tinker %% чтобы поиграть с разными вещами. (13:00) Займитесь созданием новой записи, её обновлением, получением всех записей (или всех заданий) и манипуляциями с ними. Освойтесь со всеми этими базовыми операциями. И когда будете чувствовать себя уверенно, переходите к следующему видео, где мы шагнём ещё дальше.