Can someone smart can share the design pattern they use to avoid this basic and common concurrency problem in Doctrine\Symfony?
Scenario: Each User must have a unique username.
Failed Solution:
Why It Fails: Between validating and persisting the User, the username may be taken by another User. If so, Doctrine throws a UniqueConstraintViolationException when it tries to persist the newest User.
One way to achieve what you want is by locking with the symfony LockHandler
.
Here is a simple example, using the pattern you are referring in your question:
<?php
// ...
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Filesystem\LockHandler;
use Symfony\Component\Form\FormError;
public function newAction(Request $request)
{
$task = new Task();
$form = $this->createFormBuilder($task)
->add('task', TextType::class)
->add('dueDate', DateType::class)
->add('save', SubmitType::class, array('label' => 'Create Task'))
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// locking here
$lock = new LockHandler('task_validator.lock');
$lock->lock();
// since entity is validated when the form is submitted, you
// have to call the validator manually
$validator = $this->get('validator');
if (empty($validator->validate($task))) {
$task = $form->getData();
$em = $this->getDoctrine()->getManager();
$em->persist($task);
$em->flush();
// lock is released by garbage collector
return $this->redirectToRoute('task_success');
}
$form->addError(new FormError('An error occured, please retry'));
// explicit release here to avoid keeping the Lock too much time.
$lock->release();
}
return $this->render('default/new.html.twig', array(
'form' => $form->createView(),
));
}
NB: This won't work if you run your application on multi hosts, from the documentation:
The lock handler only works if you're using just one server. If you have several hosts, you must not use this helper.
You could also override the EntityManager to create a new function like validateAndFlush($entity)
that manage the LockHandler
and the validation process itself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With