#symfony #doctrine #event-listener
#symfony #доктрина #прослушиватель событий
Вопрос:
Я пишу метод в своем приложении Symfony 3 для массового создания пользователей. Поток загружает CSV-файл со всеми необходимыми данными.
Я создал сервис, в который я записываю всю логику этой операции. Это мой сервис:
class BulkRegistration
{
private $em;
private $validator;
private $session;
public function __construct(EntityManagerInterface $em, ValidatorInterface $validator, SessionInterface $session)
{
$this->em = $em;
$this->validator = $validator;
$this->session = $session;
}
public function run(BulkRegistrationData $bulkRegistrationData){
//todo rimuovere dipendenza nascosta
$serializer = new Serializer([new ObjectNormalizer()], [new CsvEncoder()]);
$datas = $serializer->decode(file_get_contents($bulkRegistrationData->csv), 'csv');
$this->em->getConnection()->beginTransaction();
try{
foreach($datas as $data)
{
$userData = UserData::create($data);
$this->validate($userData, 'newUser');
$userCreate = User::create($userData->user);
$this->em->persist($userCreate);
$this->em->flush();
}
$this->em->getConnection()->commit();
} catch (Exception $e) {
$this->em->getConnection()->rollback();
$this->em->close();
$this->session->getFlashBag()->add('error', $e->getMessage());
return false;
}
return true;
}
private function validate ($entity, $validationGroup = null){
if($validationGroup){
$errors = $this->validator->validate($entity, null, [$validationGroup]);
}else{
$errors = $this->validator->validate($entity);
}
if (count($errors) > 0) {
$errorMessage = '';
foreach($errors as $error)
{
$errorMessage .= $error->getMessage();
}
throw new Exception($errorMessage);
}
return;
}
}
Также я написал этот EmailSubscriber для отправки электронного письма с активацией каждый раз, когда сохраняется пользователь объекта:
class EmailSubscriber implements EventSubscriber
{
private $activationEmail;
public function __construct(SendActivationEmail $activationEmail)
{
$this->activationEmail = $activationEmail;
}
public function getSubscribedEvents()
{
return array(
Events::postPersist,
);
}
public function postPersist(LifecycleEventArgs $args)
{
$entity = $args->getObject();
$entityManager = $args->getObjectManager();
if ($entity instanceof User)
{
$this->activationEmail->send($entity);
}
}
}
И это вопрос:
Подписчик событий перехватит сохраненное событие до фиксации транзакции. Я хочу либо сохранить всю строку в моей базе данных, либо ответить с нарушением и попросить пользователя изменить его CSV-файл.
Из-за этого одним из вариантов использования может быть отправленное электронное письмо с активацией, но пользователь не сохраняется в базе данных, например, для проверки нарушения одной из строк csv.
Надеюсь, я был прав, случай немного запутанный.
Ответ №1:
Я думаю, вам нужно настроить foreach на сброс только в том случае, если ошибок не было:
foreach($datas as $data) {
$userData = UserData::create($data);
try {
$this->validate($userData, 'newUser');
} catch (Exception $e) {
$this->em->getConnection()->rollback();
$this->em->close();
$this->session->getFlashBag()->add('error', $validation);
return false;
}
$userCreate = User::create($userData->user);
$this->em->persist($userCreate);
}
$this->em->flush();
$this->em->getConnection()->commit();
return true;
Комментарии:
1. Но если я не выполняю сброс в любое время, некоторая проверка пользовательских данных (например, uniqueEmail) не может быть перехвачена, поэтому у меня исключение sql, а не нарушение формы.
2. Затем вам нужно проверить уникальные поля отдельно, возможно, с помощью array_count_values().
3. Да, это может быть решением. Но я решил изменить свой способ, сделать что-то менее сложное. Я заполняю и использую массив и отправляю электронную почту вручную. Спасибо за помощь.