/** * Finds an entity by its primary key / identifier. * * @param $id The identifier. * @param int $lockMode * @param int $lockVersion * @return object The entity. */ public function find($id, $lockMode = LockMode::NONE, $lockVersion = null) { // Check identity map first if ($entity = $this->_em->getUnitOfWork()->tryGetById($id, $this->_class->rootEntityName)) { if ($lockMode != LockMode::NONE) { $this->_em->lock($entity, $lockMode, $lockVersion); } return $entity; // Hit! } if (!is_array($id) || count($id) <= 1) { // @todo FIXME: Not correct. Relies on specific order. $value = is_array($id) ? array_values($id) : array($id); $id = array_combine($this->_class->identifier, $value); } if ($lockMode == LockMode::NONE) { return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($id); } else { if ($lockMode == LockMode::OPTIMISTIC) { if (!$this->_class->isVersioned) { throw OptimisticLockException::notVersioned($this->_entityName); } $entity = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($id); $this->_em->getUnitOfWork()->lock($entity, $lockMode, $lockVersion); return $entity; } else { if (!$this->_em->getConnection()->isTransactionActive()) { throw TransactionRequiredException::transactionRequired(); } return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($id, null, null, array(), $lockMode); } } }
/** * вывести деньги * * @ApiDoc( * section="Billing API", * input="Vifeed\PaymentBundle\Form\WithdrawalType", * output={ * "class"="Vifeed\PaymentBundle\Entity\Withdrawal", * "groups"={"default"} * }, * resource=true, * statusCodes={ * 201="Returned when successful", * 400="Returned when something is wrong", * 403="Returned when the user is not authorized to use this method" * } * ) * * @return Response */ public function putWithdrawalAction() { $form = $this->createForm(new WithdrawalType()); $form->submit($this->get('request')); if ($form->isValid()) { /** @var Withdrawal $withdrawal */ $withdrawal = $form->getData(); if ($withdrawal->getWallet()->getUser() != $this->getUser()) { throw new AccessDeniedHttpException('Можно вывести только на свой кошелёк'); } if ($withdrawal->getAmount() > $this->getUser()->getBalance()) { $form->get('amount')->addError(new FormError('Недостаточно денег на балансе')); } else { $userRepo = $this->em->getRepository('VifeedUserBundle:User'); $this->em->beginTransaction(); $this->em->lock($this->getUser(), LockMode::PESSIMISTIC_WRITE); try { $withdrawal->setUser($this->getUser())->setStatus(Withdrawal::STATUS_CREATED); $this->em->persist($withdrawal); $userRepo->updateBalance($this->getUser(), -$withdrawal->getAmount()); $this->em->flush(); $this->em->commit(); } catch (\Exception $e) { $this->em->rollback(); $this->em->close(); throw $e; } $mailer = $this->get('vifeed.mailer'); $message = $mailer->renderMessage('VifeedPaymentBundle:Email:withdrawal.html.twig', ['withdrawal' => $withdrawal]); $mailer->sendMessage('Запрос на вывод средств', $message, $this->container->getParameter('withdrawal.notification.email')); $context = new SerializationContext(); $context->setGroups(array('default')); $view = new View($withdrawal, 201); $view->setSerializationContext($context); } } if (!$form->isValid()) { $view = new View($form, 400); } return $this->handleView($view); }
/** * Finds an entity by its primary key / identifier. * * @param $id The identifier. * @param int $lockMode * @param int $lockVersion * @return object The entity. */ public function find($id, $lockMode = LockMode::NONE, $lockVersion = null) { if (!is_array($id)) { $id = array($this->_class->identifier[0] => $id); } $sortedId = array(); foreach ($this->_class->identifier as $identifier) { if (!isset($id[$identifier])) { throw ORMException::missingIdentifierField($this->_class->name, $identifier); } $sortedId[$identifier] = $id[$identifier]; } // Check identity map first if (($entity = $this->_em->getUnitOfWork()->tryGetById($sortedId, $this->_class->rootEntityName)) !== false) { if (!$entity instanceof $this->_class->name) { return null; } switch ($lockMode) { case LockMode::OPTIMISTIC: $this->_em->lock($entity, $lockMode, $lockVersion); break; case LockMode::PESSIMISTIC_READ: case LockMode::PESSIMISTIC_WRITE: $persister = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName); $persister->refresh($sortedId, $entity, $lockMode); break; } return $entity; // Hit! } $persister = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName); switch ($lockMode) { case LockMode::NONE: return $persister->load($sortedId); case LockMode::OPTIMISTIC: if (!$this->_class->isVersioned) { throw OptimisticLockException::notVersioned($this->_entityName); } $entity = $persister->load($sortedId); $this->_em->getUnitOfWork()->lock($entity, $lockMode, $lockVersion); return $entity; default: if (!$this->_em->getConnection()->isTransactionActive()) { throw TransactionRequiredException::transactionRequired(); } return $persister->load($sortedId, null, null, array(), $lockMode); } }
/** * {@inheritDoc} * * @static */ public static function lock($entity, $lockMode, $lockVersion = null) { return \Doctrine\ORM\EntityManager::lock($entity, $lockMode, $lockVersion); }
/** * Acquire a lock on the given entity and refreshes the entity to have an up to date state. * * @param object $entity * @param int $lockMode * @param null $lockVersion */ public function lock($entity, $lockMode, $lockVersion = null) { parent::lock($entity, $lockMode, $lockVersion); $this->refresh($entity); }
/** * обработка показа * * @param VideoView $videoView * @param bool $skipStatusCheck * * @return boolean false, если транзакция не прошла, в остальных случаях true */ public function reckon(VideoView $videoView, $skipStatusCheck = false) { $videoViewRepo = $this->em->getRepository('VifeedVideoViewBundle:VideoView'); $userRepo = $this->em->getRepository('VifeedUserBundle:User'); $campaignRepo = $this->em->getRepository('VifeedCampaignBundle:Campaign'); $publisher = $videoView->getPlatform()->getUser(); $this->em->refresh($publisher); // обновляем энтити. Доктрина может брать его из кеша if (!$publisher->isEnabled()) { // паблишер забанен. Ничего не делаем return true; } // пользователь уже просматривал этот ролик $countViewsByViewerId = $videoViewRepo->countCampaignViewsByViewerId($videoView); if ($countViewsByViewerId['paid_views'] > 0) { return true; } $campaign = $videoView->getCampaign(); $this->em->refresh($campaign); // обновляем энтити. Доктрина может брать его из кеша // перед оплатой обновляем статус по балансу. Если пора выключать - выключаем $this->campaignManager->checkUpdateStatusOn($campaign); // если просмотр слишком короткий или кампания уже остановлена, инкрементим totalViews и выходим if (!$skipStatusCheck && !$this->checkReckonConditions($videoView)) { // засчитываем показ только если пользователь ещё не смотрел ролик if ($countViewsByViewerId['views'] == 0) { // показ участвует в статах $videoView->setIsInStats(true); $this->em->persist($videoView); $campaignRepo->incrementTotalViews($campaign); } $this->em->flush(); // на случай, если у кампании обновился статус return true; } $this->em->getConnection()->beginTransaction(); $this->em->lock($publisher, LockMode::PESSIMISTIC_WRITE); $price = $campaign->getBid(); $comissionValue = round($this->comission * $price, 2); $toPay = round($price - $comissionValue, 2); $payment = new VideoViewPayment(); $payment->setVideoView($videoView)->setCharged($price)->setComission($comissionValue)->setPaid($toPay); $userRepo->updateBalance($publisher, $toPay); $campaignRepo->addPaidView($campaign); $this->campaignManager->checkUpdateStatusOn($campaign); $videoView->setIsPaid(true)->setIsInStats(true); $this->em->persist($publisher); $this->em->persist($payment); $done = false; try { $this->em->flush(); $this->em->getConnection()->commit(); $this->em->refresh($campaign); $this->campaignManager->checkUpdateStatusOn($campaign); $this->em->flush(); // на случай, если у кампании обновился статус $done = true; } catch (\Exception $e) { $this->em->getConnection()->rollback(); // исключение не бросаем, просто откатываем транзакцию и ставим задачу снова в очередь } return $done; }
/** * {@inheritdoc} */ public function lock($entity, $lockMode, $lockVersion = null) { return $this->wrapped->lock($entity, $lockMode, $lockVersion); }