Чат PHP-разработчиков
Первая сущность. Создаём миграции и загружаем фикстуры. Работаем с шаблонизатором. Часть 1.

Первая сущность. Создаём миграции и загружаем фикстуры. Работаем с шаблонизатором. Часть 1.

Итак, начиная с этого урока, мы приступаем изучать концепции, которые вы не использовали при создании собственного MVC фреймворка, а именно - сущности, миграции и фикстуры. Как я говорил в одном из прошлых уроков, Symfony - не MVC фреймворк. Пусть вас не пугает этот факт, это совсем не значит, что, изучив Symfony, вы не сможете писать на Laravel или, упаси бог, на Yii2. Нет, на раннем этапе вы будете обращаться с Symfony как с MVC фреймворком, и только потом, с опытом, поймёте фундаментальную разницу. Например, вы можете попробовать вернуть из action что-то другое, не объект Response, а массив данных, и сразу словите ошибку

Код доступен только после покупки курса по фреймворку Symfony 4.

Поскольку Symfony - это HTTP фреймворк, он получает данные из Request'a и отправляет в виде Response.

Сущность в Symfony - это одна конкретная таблица. Если вы будете работать с постами, очевидно, вам нужна сущность Post.

Сущность можно создать двумя способами: через терминал, выполнив команду make:entity, ну или же просто вручную в папке Entity. На раннем этапе предлагаю использовать make:entity, ведь команда создаст не только сущность, но и класс-репозиторий этой сущности по работе с базой данных. Таким образом, если в том же Laravel Eloquent ORM использует паттерн ActiveRecord для работы с базой данных, то Symfony использует паттерн Репозиторий, позволяющий абстрагироваться от конкретного типа базы данных. По умолчанию, репозиторий для каждой сущности предлагает несколько простых методов выборки: findAll, find, findBy и другие.

Итак, выполните в корне проекта bin/console make:entity. Вы сразу можете передавать в качестве ключа название сущности, как это сделал я

Код доступен только после покупки курса по фреймворку Symfony 4.

Если вам будет проще, пока можете думать о сущности в качестве модели. Выполнив команду, вы заметите, что на этом консоль продолжает работать и предлагает ввести имя поля таблицы, тип данных поля, размер и проч. Мы так делать не будем, а взамен познакомимся с аннотациями. Создав сущность, просто прервите операцию с помощью Ctrl+C.

Дальше зайдите в класс Entity/Post.php, вы должны увидеть следующее:

По умолчанию, Doctrine генерирует id. Вы могли заметить нечто необычное - обширные аннотации над классом и свойствами класса. Да, именно так выглядит маппинг Doctrine ORM. Над свойствами класса, которые, я напоминаю, являются полями вашей таблицы Post, вы пишете тип данных, размер, может ли быть null и многое другое, с чем мы позже познакомимся. Над самим классом стоит следующая аннотация:

Код доступен только после покупки курса по фреймворку Symfony 4.

Она указывает, какой репозиторий обрабатывает нашу сущность.
Давайте начнём заполнять наш класс. Для начала определимся, какие у нас будут поля: title, body, slug и created_at. Этих полей будет достаточно, чтобы познакомиться с разными типами аннотаций. Тут вам не обойтись без автокомплита PhpStorm, так что советую скачать его немедленно.

Аннотация Column принимает тип данных, можно ещё указать, может ли быть поле nullable. В аннотации Length мы указываем длину, также можно указать с помощью minMessage и maxMessage, какое сообщение об ошибке будет получать пользователь, если его title не будет соответствовать допустимой длине. Над id вы могли заметить ORM\Id и ORM\GeneratedValue(), это специальные аннотации для первичного ключа.

Код доступен только после покупки курса по фреймворку Symfony 4.

Также вы должны сделать сеттеры и геттеры для каждого свойства класса, кроме id - для него нужен только геттер. В конце наш класс должен выглядеть следующим образом:

Код доступен только после покупки курса по фреймворку Symfony 4.

На данном этапе мы закончили работу с сущностью. Теперь мы должны выполнить миграцию, чтобы у нас появилась таблица в нашей базе! Открываем терминал и выполняем следующую команду:

Код доступен только после покупки курса по фреймворку Symfony 4.

У вас сгенерируется миграция в папке Migrations. Вот как она выглядит:

Внизу вы могли заметить, как Symfony вам подсказывает, что нужно сделать, чтобы запустить миграцию, а именно выполнить команду

Код доступен только после покупки курса по фреймворку Symfony 4.

Также вы должны будете подтвердить её, введя y. Вуаля, у вас появилась первая таблица! Однако, у вас нет данных. Давайте же введём вручную пару десятков значений. Шучу конечно, ничего вручную мы вводить не будем, ведь у нас есть фикстуры (fixtures)! Фикстуры - это фейковые данные, которые используются в dev-режиме, чтобы заполнить базу и проверить её работоспособность. Однако для начала нам надо скачать DoctrineFixturesBundle следующей командой:

Код доступен только после покупки курса по фреймворку Symfony 4.

Ещё скачаем популярную библиотеку Faker для генерирования рандомных данных.

Код доступен только после покупки курса по фреймворку Symfony 4.

Объясню разницу: DoctrineFixturesBundle отправляет фейковые данные, позволяет выбирать, в какой последовательности они будут генерироваться (допустим, сначала пользователи, а потом посты, если у нас связь один-ко-многим), а Faker только создаёт случайные данные. Так же работают сиды в Laravel'е, если вы с ними знакомы.

Если помните, у нас есть поле slug, обычно slug генерируется на основе названия статьи. На packagist можно найти библиотеку cocur/slugify, делающая slug как из английских слов, так и из русских. Давайте скачаем её тоже:

Код доступен только после покупки курса по фреймворку Symfony 4.

После установки DoctrineFixturesBundle у вас появится папка DataFixtures и в ней класс AppFixtures.php. В нём-то мы и будем загружать наши фейковые данные. Поначалу файл выглядит следующим образом:

ObjectManager - это класс, подготавливающий и сохраняющий данные в базе, к нему мы вернёмся позже. Мы не будем загружать фикстуры в методе load, в нём мы будем вызывать приватные методы, которые сейчас создадим. Поскольку мы работаем с постами, создадим приватный метод loadPosts, который вызовем в методе load. Для начала определимся с зависимостями: нам нужен класс Factory из библиотеки Faker и Slugify. Создадим для них свойства и заинжектим в конструктор:

Код доступен только после покупки курса по фреймворку Symfony 4.

Дальше я приведу реализацию метода loadPosts и объясню, что мы делаем:

Код доступен только после покупки курса по фреймворку Symfony 4.

Итак, мы запускаем обычный цикл, из которого понятно, что мы создадим 20 записей. Создаём класс Post. Сначала сеттим title, куда отправляем значения, сгенерированные для нас faker. Далее генерируем slug с помощью метода slugify класса Slugify, куда передаём title с помощью метода getTitle(). Поскольку сейчас мы работаем с первой записью ($i = 1), то именно title под id, равному 1, у нас и попадёт в setSlug. Это нам и нужно. Дальше мы просто сеттим body и created_at. Метод persist готовит данные, а flush всё сохраняет в конце цикла. Таким образом, наш класс выглядит следующим образом:

Осталось запустить наши фикстуры, для этого в терминале в корне проекта выполните следующую команду:

Код доступен только после покупки курса по фреймворку Symfony 4.

Подтвердите действие с помощью Y и бегите смотреть базу. Вы увидите, что все поля заполнены правильно и в поле slug у нас находится title, но с маленькими буквами и разделителями. Собственно, всё работает так, как мы этого и хотели. Во второй части статьи мы выведем все данные в шаблоне, данные по id или slug и поработаем с репозиториями!

Онлайн обучение PHP
Путь с полного нуля до джуниора!
Начать бесплатно
Читайте также
Курс программирования на PHP
Подготовка до уровня устройства на работу!
Начать бесплатно
Комментарии (2)


ilyaOrlov

После команды "doctrine:fixtures:load" вылезает ошибка:

Cannot autowire service "App\DataFixtures\AppFixtures": argument "$slugify"
   of method "__construct()" references class "Cocur\Slugify\Slugify" but no
  such service exists.

Несколько изменил конструктор, и записи в БД создались безо всяких ошибок:

public function __construct()
    {
        $this->faker = Factory::create();
        $this->slug = Slugify::create();
    }

Объясните, в чем причина такого поведения? Не получается разобраться(

kafkiansky

Дело в том, что Slugify не является внутренним сервисом Symfony. Для таких случаев фреймворк требует объявлять сервисы в config/services.yaml. В следующей статье об этой ошибке написано и показано, как исправить.

Самый понятный курс PHP
Онлайн-уроки в удобное время!
Начать бесплатно
Популярное за сутки
Онлайн-курсы PHP и MySQL
Обучение с полного нуля до уровня джуниора!
Начать бесплатно
Сейчас читают
Онлайн-курсы PHP и MySQL
Обучение с полного нуля до уровня джуниора!
Начать бесплатно
Новые статьи
Логические задачи с собеседований