Symfony 2: UniqueEntity и валидация формы

Есть стандартная задача, с которой наверняка сталкивался каждый веб-разработчик: при добавлении сущности в БД убедиться, что такой еще нет, а если есть, то отобразить соответствующее сообщение. Хочу поделиться реализацией такой задачи в Symfony 2.

Конкретный пример: необходимо реализовать функционал подписки на разные почтовые рассылки.

Есть несколько вариантов как это можно сделать:

  • можно повесить уникальный индекс на поля в таблице и отлавливать определенную ошибку c кодом 23000.
  • можно предварительно делать выборку на наличие такой записи в таблице.

В случае с Doctrine второй вариант предпочтительнее, т.к. в первом случае, при возникновении ошибки Doctrine рвет соединение с БД. Я расскажу о том, как сделать это автоматически при помощи компонентов Symfony.

У нас имеются сущности Newsletter (рассылка) и Subscriber (подписчик).


SubscribeBundle\Entity\Newsletter:
    type: entity
    table: newsletter
    fields:
        id:
            type: integer
            id: true
            generator:
                strategy: AUTO
        title:
            type: string
            length: 255
    lifecycleCallbacks: {  }


SubscribeBundle\Entity\Subscriber:
    type: entity
    table: subscriber
    fields:
        id:
            type: integer
            id: true
            generator:
                strategy: AUTO
        newsletterId:
            type: integer
            column: newsletter_id
        email:
            type: string
            length: 255
    lifecycleCallbacks: {  }
    manyToOne:
        newsletter:
            targetEntity: Newsletter
            joinColumn:
                name: newsletter_id
                referencedColumnName: id
            cascade: ["persist"]
    uniqueConstraints:
        newsletter_subscriber:
            columns: [ newsletter_id, email ]

Нам понадобится компонент Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity. Для того, чтобы воспользоваться им, необходимо добавить в src/SubscribeBundle/Resources/config/validation.yml следующее:


SubscribeBundle\Entity\Subscriber:
    constraints:
        - Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity:
            fields: [newsletterId, email]
            errorPath: email
            message: 'You already subscribed to this newsletter'

fields — параметр, который указывает на какие поля распространяется условие уникальности.
errorPath — параметр, который указывает на какое поле повесить ошибку (по умолчанию первое поле из параметра fields)
message — сообщение, которое будет показано при нарушении уникальности.

Создадим форму и передадим ей сущность Subscriber.


$subscriber = new \SubscribeBundle\Entity\Subscriber();
$form = $this->createFormBuilder($subscriber , ['attr' => ['id' => 'subscribe_form']])
    ->setAction($this->generateUrl('subscribe'))
    ->add('email', 'email', [
        'constraints' => [new NotBlank(), new Email()],
        'attr' => ['placeholder' => 'Enter your e-mail address...']
    ])
    ->add('newsletter_id', 'hidden', [
        'constraints' => new NotBlank(),
        'data' => 1 // NewsletterId should be here
    ])
    ->add('subscribe', 'submit', [
        'label' => 'Subscribe'
    ])
    ->getForm();

Теперь при валидации формы будет происходить проверка на уникальность почтового адреса для определенной рассылки.


...
$form->handleRequest($request);

if ($form->isValid()) {
    // Save entity to database
} else {
    $errors = $this->getErrorMessages($form);
    // Display somewhere received errors
}

Ну вот в принципе и всё. Для наглядности постараюсь в ближайшее время поделиться бандлом Subscribe.

Stas Kuryan

Web developer. Перфекционист в написании кода.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *