Skip to content

Instantly share code, notes, and snippets.

@faizanakram99
Last active June 20, 2019 11:40
Show Gist options
  • Save faizanakram99/adf21153247ab23ea959f2d14304199b to your computer and use it in GitHub Desktop.
Save faizanakram99/adf21153247ab23ea959f2d14304199b to your computer and use it in GitHub Desktop.
<?php
namespace Qbil\TradeBundle\Domain;
use Doctrine\ORM\EntityManagerInterface;
use Qbil\TradeBundle\Entity\Contract;
use Qbil\TradeBundle\Entity\Contractline;
use Qbil\TradeBundle\Entity\Eenheid;
use Qbil\TradeBundle\Entity\Log;
use Symfony\Component\Security\Core\User\UserInterface;
class ContractVolumeChanged implements VolumeChangedInterface
{
/**
* @var EntityManagerInterface
*/
private $entityManager;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
public function getVolumeChanged(UserInterface $user, \DateTimeInterface $date): array
{
$rawContractHistory = $this
->entityManager
->getRepository(Log::class)
->getLogs($user, $date->format('Y-m-d'), 'contract');
$totalQuantityGroupedByUnit = [];
$existingContracts = [];
/** @var Log $log */
foreach ($rawContractHistory as $log) {
$contract = $log->getContent();
if (!$contract['id'] || !$this->entityManager->find(Contract::class, $contract['id'])) {
continue;
}
if (Contract::STATUS_CONTRACT !== $contract['status']) {
continue;
}
if (in_array($contract['id'], $existingContracts)) {
continue;
}
$existingContracts[] = $contract['id'];
foreach ($contract['lines'] as $contractLine) {
if (!$contractLine['id'] || !$this->entityManager->find(Contractline::class, $contractLine['id'])) {
continue;
}
if (!isset($totalQuantityGroupedByUnit[$contractLine['unit']])) {
$totalQuantityGroupedByUnit[$contractLine['unit']] = 0;
}
$totalQuantityGroupedByUnit[$contractLine['unit']] += $contractLine['quantity'];
}
}
$totalQuantityGroupedByMeasurement = [];
foreach ($totalQuantityGroupedByUnit as $unit => $quantity) {
$unitEntity = $this->entityManager->find(Eenheid::class, $unit);
$totalQuantityGroupedByMeasurement[$unitEntity->getMeasurement()] = $quantity * $unitEntity->getSIfactor();
}
return $totalQuantityGroupedByMeasurement;
}
}
<?php
namespace Qbil\CommonBundle\Security;
use Doctrine\ORM\EntityManagerInterface;
use Qbil\TradeBundle\Domain\VolumeChangedInterface;
use Qbil\TradeBundle\Entity\Contract;
use Qbil\TradeBundle\Entity\Eenheid;
use Qbil\TradeBundle\Entity\Permission;
use Qbil\TradeBundle\Entity\Useraccount;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
class TradingVolumeLimitationVoter extends Voter
{
const CHECK = 'check';
/**
* @var AccessDecisionManagerInterface
*/
private $decisionManager;
/**
* @var EntityManagerInterface
*/
private $entityManager;
/**
* @var VolumeChangedInterface
*/
private $volumeChanged;
public function __construct(
AccessDecisionManagerInterface $decisionManager,
VolumeChangedInterface $volumeChanged,
EntityManagerInterface $entityManager
) {
$this->decisionManager = $decisionManager;
$this->volumeChanged = $volumeChanged;
$this->entityManager = $entityManager;
}
/**
* Determines if the attribute and subject are supported by this voter.
*
* @param string $attribute An attribute
* @param mixed $subject The subject to secure, e.g. an object the user wants to access or any other PHP type
*
* @return bool True if the attribute and subject are supported, false otherwise
*/
protected function supports($attribute, $subject)
{
if (!$subject instanceof Contract) {
return false;
}
if (self::CHECK !== $attribute) {
return false;
}
return true;
}
/**
* Perform a single access check operation on a given attribute, subject and token.
* It is safe to assume that $attribute and $subject already passed the "supports()" method check.
*
* @param string $attribute
* @param Contract $subject
* @param TokenInterface $token
*
* @return bool
*
* @throws \Exception
*/
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
{
$user = $token->getUser();
if (!$user instanceof Useraccount) {
return false;
}
if ($this->decisionManager->decide($token, ['ROLE_SUPER_ADMIN'])) {
return true;
}
$unsavedContractLineQuantitiesGroupedByMeasurement = [];
foreach ($subject->getContractlines() as $contractLine) {
if (!isset($unsavedContractLineQuantitiesGroupedByMeasurement[$contractLine->getUnit()->getMeasurement()])) {
$unsavedContractLineQuantitiesGroupedByMeasurement[$contractLine->getUnit()->getMeasurement()] = 0;
}
if ($contractLine->getId()) {
$unsavedContractLineQuantitiesGroupedByMeasurement[$contractLine->getUnit()->getMeasurement()] += (
array_key_exists('hoeveelheid', $contractLineChangeSet = $this->entityManager->getUnitOfWork()->getEntityChangeSet($contractLine))
? $contractLineChangeSet['hoeveelheid'][1] - $contractLineChangeSet['hoeveelheid'][0]
: 0
);
} else {
$unsavedContractLineQuantitiesGroupedByMeasurement[$contractLine->getUnit()->getMeasurement()] += $contractLine->getQuantityInSiUnit();
}
}
$totalQuantityGroupedByMeasurement = $this->volumeChanged->getVolumeChanged($user, new \DateTimeImmutable());
foreach ($this->entityManager->getRepository(Eenheid::class)->groupUnitsByMeasurement() as $measurement => $unit) {
$previouslyTradedVolume = isset($totalQuantityGroupedByMeasurement[$measurement]) ? abs($totalQuantityGroupedByMeasurement[$measurement]) : 0;
$volume = $previouslyTradedVolume + ($unsavedContractLineQuantitiesGroupedByMeasurement[$measurement] ?? 0);
if (!$user->getPermissionHandler()->hasPermissionWithVolumeOver(Permission::MUTATION_DAILY_CONTRACT_VOLUME_LIMIT, $measurement, $volume)) {
return false;
}
}
return true;
}
}
<?php
namespace Qbil\TradeBundle\Domain;
use Symfony\Component\Security\Core\User\UserInterface;
interface VolumeChangedInterface
{
public function getVolumeChanged(UserInterface $user, \DateTimeInterface $date): array;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment