Databases and the Doctrine

Symfony предоставляет Doctrine для работы с базами данных

    Базы данных и Doctrine ORM

    Symfony предоставляет все необходимые инструменты для работы с базами данных в ваших приложениях благодаря Doctrine
    Прочтите эту статью, если вам нужен низкоуровневый доступ для выполнения необработанных SQL-запросов к реляционным базам данных (аналогично PDO в PHP)

    Установка Doctrine

    composer require symfony/orm-pack composer require --dev symfony/maker-bundle

    Информация о подключении к базе данных хранится в переменной среды с именем DATABASE_URL

    В приложениях Symfony доступны миграции с помощью DoctrineMigrationsBundle, который использует внешнюю библиотеку Doctrine Database Migrations
    Документация по библиотеке Doctrine Database Migrations
    Файл конфигурации config/packages/doctrine_migrations.yaml создается автоматически или вручную

    composer require doctrine/doctrine-migrations-bundle "^3.0"


    Источник: https://symfony.com/bundles/DoctrineMigrationsBundle/current/index.html

    Настройка Doctrine ORM

    В процессе установки пакетов Doctrine, будет добавлено несколько новых каталогов: migrations/ src/Entity/ и src/Repository/
    Конфигурация почти всех установленных пакетов находится в директории config/packages/
    config/packages/doctrine.yaml - конфигурационный файл Doctrine, в котором находятся параметры подключения
    Основным параметром является DSN-строка (Data Source Name — "имя источника данных"), которая содержит информацию о подключении: учётные данные, хост, порт и т.д. По умолчанию Doctrine ищет переменную среды DATABASE_URL.
    Переменную DATABASE_URL можно инициализировать в файлах .env или .env.local

    Консольные команды DoctrineMigrationsBundle

    doctrine:migrations:current [current] Outputs the current version. doctrine:migrations:diff [diff] Generate a migration by comparing your current database to your mapping information. doctrine:migrations:dump-schema [dump-schema] Dump the schema for your database to a migration. doctrine:migrations:execute [execute] Execute a single migration version up or down manually. doctrine:migrations:generate [generate] Generate a blank migration class. doctrine:migrations:latest [latest] Outputs the latest version number doctrine:migrations:migrate [migrate] Execute a migration to a specified version or the latest available version. doctrine:migrations:rollup [rollup] Roll migrations up by deleting all tracked versions and inserting the one version that exists. doctrine:migrations:status [status] View the status of a set of migrations. doctrine:migrations:up-to-date [up-to-date] Tells you if your schema is up-to-date. doctrine:migrations:version [version] Manually add and delete migration versions from the version table. doctrine:migrations:sync-metadata-storage [sync-metadata-storage] Ensures that the metadata storage is at the latest version. doctrine:migrations:list [list-migrations] Display a list of all available migrations and their status.
    Пропуск миграций

    Вы можете пропустить отдельные миграции, явно добавив их в таблицу migration_versions:
    Doctrine предположит, что эта миграция уже была выполнена, и проигнорирует ее.

    php bin/console doctrine:migrations:version 'App\Migrations\Version123' --add


    Источник: https://symfony.com/bundles/DoctrineMigrationsBundle/current/index.html

    Автоматическое создание миграций

    Библиотека для работы с миграциями может автоматически генерировать классы миграций, сравнивая информацию с базой данных
    Предположим, что вы создаете новую сущность User (src/Entity/User.php)
    Doctrine готова помочь вам сохранить новый User объект в таблице user и извлечь его оттуда.

    php bin/console doctrine:migrations:diff

    На основе различий в схемах был создан новый класс миграции, в нем содержится SQL-код, необходимый для создания таблицы user

    php bin/console doctrine:migrations:migrate


    Источник: https://symfony.com/bundles/DoctrineMigrationsBundle/current/index.html

    Ручные таблицы, не управляемые Doctrine

    По умолчанию такие таблицы будут помечены для удаления командой doctrine:migrations:diff
    Можно настроить doctrine/dbal для игнорирования некоторых таблиц:

    # config/packages/doctrine.yaml doctrine: dbal: schema_filter: ~^(?!t_)~ # Ignore all tables prefixed by `t_`


    Источник: https://symfony.com/bundles/DoctrineMigrationsBundle/current/index.html

    Создание пользователя и базы данных

    #Создать роль в базе данных CREATE ROLE user1; #Добавить пароль для пользователя ALTER ROLE user1 WITH LOGIN PASSWORD 'password'; #Создать базу данных CREATE DATABASE db1 OWNER user1 ENCODING = 'UTF-8' LC_COLLATE = 'ru_RU.UTF-8' LC_CTYPE = 'ru_RU.UTF-8'; DATABASE_URL="postgresql://user1:password@127.0.0.1:5432/db1?serverVersion=16&charset=utf8"

    Если имя пользователя, пароль, имя хоста или базы данных содержат специальные символы, используемые в URI (например, : / ? # [ ] @ ! $ & ' ( ) * + , ; =), их необходимо закодировать. Полный список зарезервированных символов приведен в RFC 3986. Для кодирования можно использовать функцию urlencode или процессор переменных окружения urlencode. В этом случае необходимо удалить префикс resolve: в config/packages/doctrine.yaml, чтобы избежать ошибок: url: '%env(DATABASE_URL)%'


    Чтобы избежать проблем с URL-кодированием при использовании специальных символов в учетных данных, можно использовать отдельные параметры подключения вместо формата URL. Определите каждое значение как отдельную переменную среды и заключите его в одинарные кавычки в файле .env, чтобы такие символы, как $ и #, не интерпретировались:

    DATABASE_PASSWORD='p@ss$wo#rd'

    Затем настройте Doctrine на использование отдельных параметров:

    # config/packages/doctrine.yaml doctrine: dbal: user: '%env(DATABASE_USER)%' password: '%env(DATABASE_PASSWORD)%' host: '%env(DATABASE_HOST)%' port: '%env(DATABASE_PORT)%' dbname: '%env(DATABASE_NAME)%' driver: pdo_pqsql

    Существует множество других команд Doctrine. Запустите php bin/console list doctrine , чтобы увидеть полный список.


    Источник: https://symfony.com/doc/current/doctrine.html

    Создание класса сущностей

    С помощью команды make:entity вы можете создать класс сущности и необходимые поля в интерактивном режиме

    php bin/console make:entity

    После подтверждения будет создан файл src/Entity/Profile.php
    Этот класс называется «сущностью». Теперь можно сохранять объекты Profile и запрашивать их из profile таблицы в своей базе данных. Каждое свойство Product сущности можно сопоставить со столбцом в этой таблице. Обычно это делается с помощью атрибутов — #[ORM\Column(...)] комментариев, которые видно над каждым свойством.


    Вы можете передать --with-uuid или --with-ulid в make:entity. Используя компонент Uid Symfony, вы можете создать сущность с типом id как Uuid или Ulid вместо int.

    Типы полей сущностей

    Ознакомьтесь с перечнем типов сопоставления Doctrine
    https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/basic-mapping.html#reference-mapping-types


    Один из таких типов основан на перечисляемых типах данных PHP, которые позволяют определить закрытый набор возможных значений для данного типа. Это делает их подходящим решением для моделирования свойств сущностей, которые могут принимать только заранее определенный набор значений.

    Подробнее: https://symfony.com/doc/current/doctrine.html#entity-field-types

    Миграции: создание таблиц/схемы базы данных

    #Для создания миграции
    php bin/console make:migration created: migrations/Version20260507165112.php Success! Review the new migration then run it with php bin/console doctrine:migrations:migrate #Для создания сущности (таблицы) в базе данных #Выполнить миграцию php bin/console doctrine:migrations:migrate WARNING! You are about to execute a migration in database "apimega" that could result in schema changes and data loss. Are you sure you wish to continue? (yes/no) [yes]: > yes [notice] Migrating up to DoctrineMigrations\Version20260507165112 [notice] finished in 16.2ms, used 22M memory, 1 migrations executed, 3 sql queries [OK] Successfully migrated to version: DoctrineMigrations\Version20260507165112

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


    Миграции и добавление новых полей

    Можно отредактировать класс сущности, чтобы добавить новое свойство. Но также можно снова использовать make:entity:

    php bin/console make:entity Class name of the entity to create or update > Profile

    В процессе создания нового свойства, в класс Profile будет добавлено свойство и методы set*() get*()


    После редактирования класс необходимо сгенерировать новую миграцию
    Система миграции умна. Она сравнивает все ваши сущности с текущим состоянием базы данных и генерирует SQL-запросы, необходимые для их синхронизации

    #Создать миграцию php bin/console make:migration #Выполнить миграцию php bin/console doctrine:migrations:migrate

    Если вы предпочитаете добавлять новые свойства вручную, команда make:entity может сгенерировать для вас методы получения и установки значений.

    php bin/console make:entity --regenerate

    Если вы внесли какие-то изменения и хотите перегенерировать все методы получения и установки значений, также передайте --overwrite.


    Источник: https://symfony.com/doc/current/doctrine.html#migrations-adding-more-fields

    Создание контроллера сущности и сохранение в базе данных

    #Создать контроллер php bin/console make:controller ProfileController Do you want to generate PHPUnit tests? [Experimental] (yes/no) [no]: > created: src/Controller/ProfileController.php created: templates/profile/index.html.twig Success! #src/Controller/ProfileController.php namespace App\Controller; use App\Entity\Profile; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; final class ProfileController extends AbstractController { #[Route('/profile', name: 'add_profile')] public function createProfile(EntityManagerInterface $entityManager): Response { $profile = new Profile(); $profile->setNameUser('Admin'); $profile->setPasswordUser('password'); //сохранить объект Product (запросы пока не выполняются) $entityManager->persist($profile); //фактически выполняет запросы (например, запрос INSERT) $entityManager->flush(); return new Response($profile->getId()); } }

    Аргумент EntityManagerInterface $entityManager указывает Symfony на необходимость внедрить сервис Entity Manager в метод контроллера. Этот объект отвечает за сохранение объектов в базе данных и их извлечение из нее.
    Вызов persist($product) указывает Doctrine на необходимость «управления» объектом
    При вызове метода flush() Doctrine просматривает все объекты, которыми она управляет, чтобы определить, нужно ли сохранять их в базе данных. В этом примере данных объекта $profile нет в базе данных, поэтому менеджер сущностей выполняет INSERT запрос, создавая новую строку в таблице profile


    Независимо от того, создаете вы объекты или обновляете их, процесс всегда один и тот же: Doctrine достаточно умен, чтобы определить, нужно ли выполнить INSERT или UPDATE для вашего объекта.

    После перехода на страницу /profile, будет добавлен пользователь в таблицу базы данных

    Проверить наличие данной строки можно с помощью следующей команды

    php bin/console dbal:run-sql 'SELECT * FROM profile'
    Связывание сущностей

    Созданные сущности, конференция и комментарий, должны быть взаимосвязаны. Например сущности User, Blog, Comment, то есть комментарий будет принадлежать определенному блогу и пользователю
    Используйте команду make:entity ещё раз, чтобы добавить эту связь в существующий класс сущности, но только если свойство не существует
    В интерактивном режиме, если в качестве ответа на вопрос о типе данных вы введёте ?, то вы получите список всех поддерживаемых типов, где в качестве типа можно выбрать тип связи и существующий тип сущности

    symfony console make:entity Conference Your entity already exists! So let's add some new fields! New property name (press to stop adding fields): > comments Field type (enter ? to see all types) [string]: > OneToMany What class should this entity be related to?: > Comment A new property will also be added to the Comment class...

    В результате выполнения данной команды в класс сущности будет добавлено новое свойство типа Comment и соответствующие ему атрибуты

    Отношения doctrine

    Существует два основных типа отношений/связей:
    ManyToOne / OneToMany


    ManyToMany - необходима в тех случаях, когда обе стороны связи могут иметь множество элементов другой стороны (например классы и ученики)

    ManyToOne - например мы создаем сущность comments (комментарии) и добавляем в его класс свойство posts (посты) класса Post с типом отношения ManyToOne (много комментариев к одному посту)
    OneToMany - в классе Post (посты) создаем свойство comments класса Comment c типом отношения OneToMany (один пост к многим комментариям)

    При создании сущностей Doctrine обеспечивает сохранение этих связей.

    .... use App\Entity\Post; use App\Entity\Comment; .... #[Route('/post', name: 'posts')] public function index(EntityManagerInterface $entityManager): Response { $post = new Post(); $post->setName('Computer Peripherals'); $comment = new Comment(); $comment->setText('This text ...'); $post->setComments($comment); $entityManager->persist($post); $entityManager->persist($comment); $entityManager->flush(); php bin/console doctrine:migrations:diff php bin/console doctrine:migrations:migrate ....
    Выборка связанных объектов

    В этом примере сначала находим пост по его id, далее получаем все связанные с ним комментарии

    use App\Entity\Product; // ... class PostController extends AbstractController { public function show(PostRepository $postRepository, int $id): Response { $post = $postRepository->find($id); // ... $comments = $post->getComments()->getText(); // ... } }

    Поскольку мы сопоставили необязательную часть OneToMany, вы также можете выполнять запросы в обратном направлении

    class PostController extends AbstractController { public function show(CommentRepository $commentRepository, int $id): Response { $comment = $commentRepository->find($id); // ... $posts = $comment->getPosts()->getName(); // ... } }
    Объединение связанных записей

    Если вы заранее знаете, что вам понадобится доступ к обоим объектам, можно избежать второго запроса, выполнив объединение в исходном запросе. Добавьте в ProductRepository следующий метод:

    // src/Repository/ProductRepository.php // ... class ProductRepository extends ServiceEntityRepository { public function findOneByIdJoinedToCategory(int $productId): ?Product { $entityManager = $this->getEntityManager(); $query = $entityManager->createQuery( 'SELECT p, c FROM App\Entity\Product p INNER JOIN p.category c WHERE p.id = :id' )->setParameter('id', $productId); return $query->getOneOrNullResult(); } }

    Теперь вы можете использовать этот метод в своем контроллере для запроса Product объекта и связанных с ним Category в рамках одного запроса:

    // src/Controller/ProductController.php // ... class ProductController extends AbstractController { public function show(ProductRepository $productRepository, int $id): Response { $product = $productRepository->findOneByIdJoinedToCategory($id); $category = $product->getCategory(); // ... } }

    Более подробную информацию и примеры использования других типов связей (например, «один к одному», «многие ко многим») можно найти в документации Doctrine по отображению ассоциаций
    https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/association-mapping.html


    Источник: https://symfony.com/doc/current/doctrine/associations.html#joining-related-records

    DoctrineMigrationsBundle
    Проверка объектов

    Источники
    Последнее изменение: 04.06.2026 04:03


    Связанные темы
    Здесь пока нет комментариев
    Добавлять комментарии могут только авторизованные пользователи

    Авторизоваться
    Я буду рекламой
    Я тоже буду рекламой
    И я
    ВВЕРХ