Skip to content

Instantly share code, notes, and snippets.

@dmz9
Last active May 2, 2018 19:21
Show Gist options
  • Save dmz9/1a93b354c025aec3e00042cae745e8af to your computer and use it in GitHub Desktop.
Save dmz9/1a93b354c025aec3e00042cae745e8af to your computer and use it in GitHub Desktop.
Sequence per entity for doctrine with pessimistic lock
<?php
class BusinessTransactionHandler{
public function persistOrder( Order $order, EntityManager $em ) {
$em->beginTransaction();
try {
$counter = $em->find( "AppBundle:ShopOrderCounter",
$order->getShop()
->getOrderCounter()
->getId(),
LockMode::PESSIMISTIC_WRITE );
} catch ( OptimisticLockException $e ) {
throw new HandlerException( "Ошибка блокировки", $e );
} catch ( TransactionRequiredException $e ) {
throw new HandlerException( "Ошибка блокировки", $e );
} catch ( ORMException $e ) {
throw new HandlerException( "Ошибка блокировки", $e );
}
$order->setNumber( $counter->nextNumber() );
$em->persist( $order );
try {
$em->flush();
$em->commit();
} /** @noinspection PhpRedundantCatchClauseInspection */ catch ( UniqueConstraintViolationException $unique ) {
$em->rollback();
throw new ConflictHttpException( "Такой заказ уже существует", $unique );
} catch ( \Exception $exception ) {
$em->rollback();
throw new BadRequestHttpException( "Ошибка сервера при записи данных заказа", $exception );
}
}
}
<?php
namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* Shop
*
* @ORM\Table(name="shop")
* @ORM\Entity(repositoryClass="AppBundle\Repository\ShopRepository")
*/
class Shop {
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var ArrayCollection
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Order", mappedBy="shop")
*/
private $orders;
/**
* @var ShopOrderCounter
* @ORM\OneToOne(targetEntity="ShopOrderCounter", cascade={"all"})
* @ORM\JoinColumn(name="order_counter", referencedColumnName="id")
*/
protected $orderCounter;
/**
* @return ShopOrderCounter
*/
public function getOrderCounter() {
return $this->orderCounter;
}
/**
* Shop constructor.
*/
public function __construct() {
$this->orders = new ArrayCollection();
$this->orderCounter = new ShopOrderCounter();
}
/**
* @return int
*/
public function getId() {
return $this->id;
}
public function registerOrder( Order $order ) {
if ( ! $this->orders->contains( $order ) ) {
$this->orders->add( $order );
}
}
}
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* ShopNumber
*
* @ORM\Table(name="shop_order_counter")
* @ORM\Entity(repositoryClass="AppBundle\Repository\ShopOrderCounterRepository")
*/
class ShopOrderCounter {
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* @var int следующий свободный номер заказа
* @ORM\Column(name="next_order_number", type="integer")
*/
protected $nextOrderNumber;
/**
* ShopNumber constructor.
*
* @param int $nextOrderNumber
*/
public function __construct() {
$this->nextOrderNumber = 1;
}
/**
* Get id
*
* @return int
*/
public function getId() {
return $this->id;
}
/**
* @return int
*/
public function nextNumber() {
$next = $this->nextOrderNumber;
$this->nextOrderNumber = $next + 1;
return $next;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment