Есть стандартная задача, с которой наверняка сталкивался каждый веб-разработчик: при добавлении сущности в БД убедиться, что такой еще нет, а если есть, то отобразить соответствующее сообщение. Хочу поделиться реализацией такой задачи в 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.