Создание БД и установка Doctrine ORM

Подключение базы данных в Docker. Конфигурирование через переменными окружения. Плюсы и минусы подходов DB-First и Code-First. Обзор Doctrine ORM. Установка библиотеки и регистрация EntityManager в DI-контейнере.

  • 00:00:06 Обзор архитектуры
  • 00:02:33 Подходы DB First и Code First
  • 00:05:35 Готовые ORM
  • 00:06:40 Выбор СУБД
  • 00:08:16 Поднятие PostgreSQL в Docker
  • 00:11:03 Подключение к БД из PhpStorm
  • 00:12:24 Установка pdo_pgsql для PHP
  • 00:14:09 Установка Doctrine ORM
  • 00:15:35 Создание подключения
  • 00:17:08 Конфигурирование сущностей
  • 00:20:06 Работа с EntityManager и UnitOfWork
  • 00:23:45 Подключение Doctrine ORM
  • 00:27:25 Стратегия именования полей
  • 00:28:53 Параметры подключения
  • 00:30:59 Настройки для разных окружений
  • 00:32:15 Конфликт доступа к папке var
  • 00:35:12 Подключение готовых консольных команд
  • 00:39:17 Индивидуальное подключение команд
  • 00:41:59 Проблема склейки конфигураций
  • 00:43:12 Конфигурация с Laminas Config Aggregator
  • 00:46:01 Обзор результата
Скрытый контент (код, слайды, ...) для подписчиков. Открыть →
Дмитрий Елисеев
elisdn.ru
Комментарии (31)
Arunas

Спасибо.

Ответить
Роман

Смотрю на это все и не понимаю, как один человек столько может знать не только в теории но и на практике.

Ответить
Александр

и не говори )) я все еще пытаюсь все это дело с бд , запустить второй день

Ответить
Arunas

Какой connection string url будет, если БД устроинна с наруже, не в докере? Если можете, напишите, пожалуйста (надо как то корегировать api/config/common/doctrine.php или нет).

Ответить
Дмитрий Елисеев

Тогда вместо хоста api-postgres указывают IP-адрес сервера с БД.

Ответить
Arunas

спасибо.

Ответить
Arunas

Как правильно делаются backup БД при работе в докерском окружении? Можно этот backup БД делать с кроном, какая практика с backup БД? (если можете, пакажите пример) Влиялить или нет на производительност сайта или надёжность данных backup БД?

Ответить
Дмитрий Елисеев

Можно обычным вызовом pgdump внутри контейнера:

docker-compose exec api-postgres pgdump ...
Ответить
Роман

Добрай день Дмитрий,спасибо за качественный материал, вопрос не по теме, но будет ли в курсе рассмотрена тема поднятие нескольких бд master-slaves (в частности для продакта), и работа с ними, а также разные типы блокировки postgresql ? Заранее блогадарю

Ответить
Дмитрий Елисеев

Репликации не будет. Но для этого можно взять образ bitnami/postgresql и настроить как в примере Setting up a streaming replication.

При работе с Doctrine рассмотрим оптимистическую блокировку. Во многих случаях её будет достаточно.

Ответить
Олег

не очень понятно, почему на 39:25 в консоль не вылетает ошибка, ведь array_merge_recursive сформирует вот такое значение под ключем cache_dir => array('DIR из common', 'null из dev'), а потом передаст это значение в createAnnotationMetadataConfiguration, и упадет в фаталом, что ждет строку, а не массив Как так?

Ответить
Олег

array_replace_recursive - не усмотрел

Ответить
Андрей

Вопрос о правах записи в одну и ту же папку кешу между контейнерами php-cli и php-fpm. Почему мы сделали запись в разные папки только для dev окружения, а для продакшена оставили без изменений? Ведь на продакшене такая же проблема будет...

Ответить
Дмитрий Елисеев

На продакшене не будет. Там контейнеры php-cli и php-fpm пишут каждый в свою внутреннюю папку, а не как в dev в одну общую, примонтированную через volume.

Ответить
Олег

Дмитрий, поясните пжл, что это за volumes:

 api-postgres:

Что это значит и где по факту хранятся данные?

Ответить
Дмитрий Елисеев

Значит, что создаётся вольюм с настройками по умолчанию.

В случае docker-compose хранятся в папке /var/lib/docker/volumes/auction_api-postgres

Ответить
elmut
<?php

use Shared\Domain\ValueObjects\UserId;

/**
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks
 * @ORM\Table(name="auth_users")
 */
class AuthUser
{
    /**
     * @ORM\Column(type="user_id")
     * @ORM\Id
     */
    private UserId $id;

    /**
     * @ORM\OneToOne(targetEntity="UserPassword", cascade={"persist", "remove"}, mappedBy="userId")
     */
    protected ?UserPassword $joinPassword = null;
}

/**
 * @ORM\Entity()
 * @ORM\Table(name="auth_user_password")
 * @ORM\HasLifecycleCallbacks()
 */
class UserPassword
{
    /**
     * @ORM\Column(type="user_id")
     * @ORM\Id
     * @ORM\OneToOne(targetEntity="AuthUser", inversedBy="joinPassword")
     */
    private UserId $userId;

    /**
     * @ORM\Column(type="string")
     */
    private string $login;
}

Дмитрий, а как сделать так что бы AuthUser и UserPassword у них был один id?

Ответить
Дмитрий Елисеев

Со связью @ORM\OneToOne никак. Только вручную без неё.

Ответить
Алексей

Дмитрий, а есть планы в одном из будущих учебных проектов использовать Cycle ORM? Было бы любопытно.

Ответить
Дмитрий Елисеев

Может будет если будем что-то запускать в RoadRunner.

Ответить
Николай

Дмитрий, добрый день! Команда

docker-compose run --rm api-php-cli composer app

выдает ошибку

PHP Fatal error:  Uncaught Error: Class "Doctrine\Common\Cache\ArrayCache" not found in /app/config/common/doctrine.php:33

ArrayCache и FilesystemCache в doctrine/orm 2.9 больше не доступны?

Ответить
Николай

Проблема решена. Нашел коммит от 12 мая "Migrated to PSR cache". Все заработало.

Ответить
bogdan

спасибо) как раз таже проблема

Ответить
maxbrown1

спасибо, помогло)

Ответить
Sam

Дмитрий, при запуске make init получаю слудущую ошибку:

ERROR: for api-postgres  Get "//registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)

Подскажите. что это может быть?

Update: в файле /etc/resolv.conf добавить вначале

nameserver 8.8.8.8

nameserver 8.8.4.4

nameserver 127.0.0.53

Ответить
Дмитрий Елисеев

Да, это может быть проблема подключения к реестру докерхаба. Свежие DNS могут помочь.

Ответить
Максим (@myks92)

Доброго дня! Возник вопрос по оптимистической блокировке в DDD при использовании Doctrine.

Суть. Мы имеем корень агрегата с полем $version и аннотацией @ORM\Version(), которое нужно для оптимистической блокировки. При изменении сущности корня агрегата поле version увеличивается на 1, а вот при изменении вложенных сущностей вроде @ORM\ManyToMany(targetEntity="Role") поле версии у агрегата не увеличивается на 1. Из-за чего оптимистическая блокировка работает не правильно.

Почитав документацию на этот счёт сама доктрина нам предлагает пойти путём добавления собственного поля агрегации

В Java видел такое решение, как принудительное изменение версии OPTIMISTIC_FORCE_INCREMENT. В доктрине такого не нашёл в текущих версиях, однако в 2015 году в доктрине присутствовала такая блокировка, затем её убрали

Подскажите, пожалуйста, как решается данная проблема с doctrine при изменении вложенных сущностей?

Для себя придумал такое решение, что можно создать вместо созданного вами интерфейса AggregateRoot создать абстрактный класс AgregateRoot в котором реализовать данную функцию принудительного изменения версии.

Ответить
Максим (@myks92)

В продолжении комментария… Описал проблему и её решение на Хабр.

Так же решил пойти дальше — внёс вклад в DoctrineExtensions написал issue и добавил своё решение в виде pull-request. Надеюсь, что решение окажется удачным и его одобрят.

Если будет желание и время — присоединяйтесь. Не судите строго)

Ответить
Дмитрий Елисеев

Да, проблема есть. Обычно решал именно через обновление своего поля $updatedAt.

Ответить
slo_nik

Доброй ночи, Дмитрий.

Возникла непонятная для меня проблема.

В Dockerfile для fpm, cli устанавливаю pgsql, всё по Вашим примерам сделано.

RUN apk add --no-cache postgresql-dev bash coreutils \
&& docker-php-ext-configure pgsql --with-pgsql=/usr/local/pgsql \
&& docker-php-ext-install pdo_pgsql

Проблема заключается в том, что в зависимости от версии alpine существенно меняется размер итогового образа. Например, при версии php:8.1-fpm-alpine3.19 размер prod образа fpm будет 795MB, а при версии php:8.1-fpm-alpine3.16 размер будет составлять 594MB. При этом директория app весит 197MB, всё остальное приходится в на /usr/lib, что тоже много. Получается, что мои итоговые prod образы весят от 700 до 900 MB при версии alpine 3.19

Я пробовал заменять postgresql-dev на libpg-dev, тогда размер образов при смене версии alpine остаётся без изменений +-5MB

Скажите, при использовании postgresql-dev такой большой разбег по размерам образов нормальное поведение или нет?

Ответить
Дмитрий Елисеев

Да, можно теперь поменять на libpq-dev. Так будет экономнее.

Ответить
Зарегистрируйтесь или войдите чтобы оставить комментарий

Или войти через:

Yandex
MailRu
GitHub
Google