Урок 6: Базы данных и Doctrine ORM в Symfony

В 6-ом уроке мы изучимв один из ключевых аспектов Symfony, это работу с базами данных через Doctrine ORM. Этот урок станет фундаментом для всех ваших будущих проектов, где требуется хранение, управление и запросы к данным. Мы разберем:

  1. Установку и настройку Doctrine,
  2. Создание сущностей (Entities) и репозиториев (Repositories),
  3. Миграции (make:migration и doctrine:migrations:migrate),
  4. Основы DQL (Doctrine Query Language).

Установка и настройка Doctrine

Doctrine это ORM (Object-Relational Mapper), который превращает таблицы базы данных в объекты PHP. Вместо написания SQL-запросов вы работаете с классами и методами. Это удобно, безопасно и поддерживает принципы ООП.

Установка Doctrine

  1. Добавляем Doctrine в проект через Composer:
bash
composer require symfony/orm-pack
composer require --dev symfony/maker-bundle

Пакет orm-pack добавляет Doctrine и его зависимости, а maker-bundle поможет генерировать сущности.

  1. Настройка подключения к БД в файле .env:
env
DATABASE_URL="mysql://root:password@127.0.0.1:3306/symfony_db?serverVersion=8.0"

Замените rootpasswordsymfony_db и serverVersion на свои значения.
Doctrine поддерживает MySQL, PostgreSQL, SQLite и другие СУБД.

  1. Проверка подключения:
bash
php bin/console doctrine:database:create

Если видите сообщение Created database symfony_db, всё готово!

Сущности (Entities) и репозитории (Repositories)

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

Сущность это PHP-класс, который отображается на таблицу в БД.

Пример: Создадим сущность Product.

bash
php bin/console make:entity Product

Следуйте подсказкам и добавьте поля:

  • name (string, 255),
  • price (float),
  • description (text).

Результат:

php
// src/Entity/Product.php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: ProductRepository::class)]
class Product
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    private ?string $name = null;

    #[ORM\Column]
    private ?float $price = null;

    #[ORM\Column(type: 'text')]
    private ?string $description = null;

    // Геттеры и сеттеры...
}

Репозитории

Репозиторий это класс для работы с данными сущности. Doctrine автоматически генерирует его при создании сущности.

Пример использования:

php
// src/Repository/ProductRepository.php

namespace App\Repository;

use App\Entity\Product;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;

class ProductRepository extends ServiceEntityRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, Product::class);
    }

    // Кастомный метод для поиска товаров дороже указанной цены
    public function findProductsMoreExpensiveThan(float $price): array
    {
        return $this->createQueryBuilder('p')
            ->andWhere('p.price > :price')
            ->setParameter('price', $price)
            ->orderBy('p.price', 'ASC')
            ->getQuery()
            ->getResult();
    }
}

Миграции

Миграции это версионирование структуры БД. Они позволяют безопасно применять изменения схемы данных.

Генерация миграции

После изменения сущности (например, добавления поля isPublished):

bash
php bin/console make:migration

Doctrine сравнит текущую структуру БД с маппингом сущностей и сгенерирует SQL-запрос в файле migrations/Version20230401...php.

Применение миграции

bash
php bin/console doctrine:migrations:migrate

Всегда проверяйте сгенерированный SQL перед выполнением!

Основы DQL (Doctrine Query Language)

DQL это объектно-ориентированный диалект SQL, работающий с сущностями, а не таблицами.

Пример DQL-запроса

Найдем товары с ценой выше 1000:

php
// Внутри ProductRepository

public function findExpensiveProducts(): array
{
    $entityManager = $this->getEntityManager();
    $query = $entityManager->createQuery(
        'SELECT p 
        FROM App\Entity\Product p 
        WHERE p.price > 1000 
        ORDER BY p.price ASC'
    );
    return $query->getResult();
}

DQL или Query Builder

  • DQL подходит для сложных запросов.
  • Query Builder удобен для поэтапного построения запроса:
php
$queryBuilder = $this->createQueryBuilder('p')
    ->where('p.price > :price')
    ->setParameter('price', 1000)
    ->orderBy('p.price', 'ASC')
    ->getQuery();

Практические задачи

  1. Создайте сущность User с полями: email (string), createdAt (datetime).
  2. Добавьте миграцию для новой сущности и выполните ее.
  3. Напишите DQL-запрос, который выбирает пользователей, зарегистрированных после 1 января 2023 года.
  4. Создайте метод в репозитории для поиска товаров по части названия (используйте LIKE).

Пример решения задачи 4

php
// В ProductRepository

public function searchByName(string $keyword): array
{
    return $this->createQueryBuilder('p')
        ->andWhere('p.name LIKE :keyword')
        ->setParameter('keyword', "%{$keyword}%")
        ->getQuery()
        ->getResult();
}

Вы освоили основы Doctrine ORM, от создания сущностей до работы с миграциями и DQL. Теперь ваши приложения могут взаимодействовать с БД на профессиональном уровне. Не останавливайтесь, полный курс по Symfony для начинающих ждет вас.