<?php
namespace App\Controller;
use App\Entity\AccountTransactions;
use App\Entity\Auctions;
use App\Entity\AuctionVehicleBids;
use App\Entity\AuctionVehicles;
use App\Entity\ContentPages;
use App\Entity\VehicleClients;
use App\Entity\VehicleMakers;
use App\Entity\VehicleModels;
use App\Entity\Vehicles;
use App\Service\VehicleHelper;
use Doctrine\ORM\Query\Expr\Math;
use DoctrineExtensions\Query\Mysql\Date;
use Knp\Component\Pager\PaginatorInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* Class DefaultController
* @package App\Controller
*/
class DefaultController extends AbstractController
{
/**
* @param Request $request
*
* @Route("/", name="homepage")
* @Method("GET")
*
* @return \Symfony\Component\HttpFoundation\Response
* @throws \Doctrine\ORM\NonUniqueResultException
*/
public function indexAction(Request $request, PaginatorInterface $paginator)
{
$em = $this->getDoctrine()->getManager();
//the video to show with auction info
$video = $em->getRepository(ContentPages::class)->findOneBy(['keyword' => 'video']);
$locale = $request->getLocale();
$session = $request->getSession();
$data = $this->getOngoingAuctionVehicles($request, $paginator);
// to set init before load page and jq
$countDown = [];
$checkNoMinus = true;
$auctionFinished = false;
if($data['endDate']){
// set default timezone
date_default_timezone_set('Asia/Riyadh'); // CDT
$datetime1 = new \DateTime();
$datetime2 = $data['endDate'];
$interval = $datetime1->diff($datetime2);
$days= $interval->format('%a');
$hours =$interval->format('%h') ;
$mins = $interval->format('%i');
if($datetime2 < $datetime1 ){
$checkNoMinus = false;
if($days <= 5){
$auctionFinished = true;
}
}else{
$countDown['days'] = $days ;
$countDown['hours'] = $hours ;
$countDown['mins'] = $mins ;
}
}
// index.html.twig will be used if there is an ongoing auction. Otherwise: index-without-auction.html.twig
$homepageTemplate = $this->getParameter('homepage_template');
$auctionTermsContent = $em->getRepository(ContentPages::class)->findOneBy(['keyword' => 'auction_terms']);
// replace this example code with whatever you need
return $this->render($homepageTemplate, [
'searchForm' => $data['searchForm']->createView(),
'auctionVehicles' => $data['auctionVehicles'],
'locale' => $locale,
'imageRealPath' => $data['imageRealPath'],
'totalResult' => $data['totalResult'],
'loggedUser' => $this->getUser(),
'endDate' => $data['endDate'],
'auctionStatus' => $data['auctionStatus'],
'countDown' => $countDown,
'checkNoMinus' => $checkNoMinus,
'auctionFinished' => $auctionFinished,
'auction' => $data['auction'],
'video' => $video,
'auctionTermsContent' => $auctionTermsContent
/* 'homepage' => $this->getParameter('homepage')*/
]);
}
/**
* @param Request $request
*
* @Route("/auctionVehicles", name="auction_vehicles")
* @Method("GET")
*
* @return \Symfony\Component\HttpFoundation\Response
* @throws \Doctrine\ORM\NonUniqueResultException
*/
public function auctionVehicles(Request $request)
{
$data = $this->getOngoingAuctionVehicles($request, 'auctionVehicles');
return $this->render('default/auction_vehicles.html.twig', [
'searchForm' => $data['searchForm']->createView(),
'auctionVehicles' => $data['auctionVehicles'],
'locale' => $data['locale'],
'imageRealPath' => $data['imageRealPath'],
'totalResult' => $data['totalResult']
]);
}
/**
* @param $vehicleId
* @param Request $request
* @param UserInterface $user
*
* @Route("/vehicleDetails/{vehicleId}", name="vehicle_details")
* @Method({"GET", "POST"})
*
* @return \Symfony\Component\HttpFoundation\Response
* @throws \Doctrine\DBAL\ConnectionException
* @throws \Doctrine\ORM\NonUniqueResultException
* @throws \Doctrine\ORM\ORMException
* @throws \Doctrine\ORM\OptimisticLockException
*/
public function vehicleDetailsAction($vehicleId, Request $request, TranslatorInterface $translator, AuthorizationCheckerInterface $auth, UserInterface $user = null)
{
// if the user was not logged in and press the login url in this action page we redirect him to this action and send login parameter equal 1 with the url
$requireLogin = $request->get('login');
$loggedinUser = $auth->isGranted(['IS_AUTHENTICATED_FULLY', 'IS_AUTHENTICATED_REMEMBERED']);
if ($requireLogin && !$loggedinUser) {
throw $this->createAccessDeniedException();
} elseif ($requireLogin && $loggedinUser) { // after redirect the logged in user we remove the parameter login
$request->query->remove('login');
return $this->redirectToRoute('vehicle_details', array('vehicleId' => $vehicleId));
}
$em = $this->getDoctrine()->getManager();
$locale = $request->getLocale();
$vehicle = $em->getRepository(Vehicles::class)->find($vehicleId);
$imageRealPath = $this->getParameter('vehicle_uploaded_files') . '/';
if ($user) {
$auctionVehicle = $em->getRepository(Auctions::class)->getAuctionVehicleAtOngoingAuction($vehicleId);
$auctionVehicleId = $auctionVehicle->getAuctionVehicleId();
$auctionVehicleBid = $em->getRepository(AuctionVehicleBids::class)->findOneBy(['auctionVehicle' => $auctionVehicleId, 'bidder' => $user->getUserId()]);
if (!$auctionVehicleBid) {
$auctionVehicleBid = new AuctionVehicleBids();
}
} else {
$auctionVehicleBid = new AuctionVehicleBids();
}
$bidForm = $this->createFormBuilder($auctionVehicleBid)
->setMethod('POST')
->add('bidValue', TextType::class, array(
'required' => false,
'label' => 'add your bid',
'translation_domain' => 'vehicles',
'data' => $auctionVehicleBid->getBidValue()
))
->getForm();
$bidForm->handleRequest($request);
if ($bidForm->isSubmitted()) {
//a default success flash message
$session = $request->getSession();
$vehicleClient = $em->getRepository(VehicleClients::class)->find($user->getUserId());
//[1.1] suspend auto-commit until ensuring that balance funds covers all auction security locks
$em->getConnection()->beginTransaction();
//[1.2] insert\update\delete bids according user data entries
$transactionsRepo = $this->getDoctrine()->getManager()->getRepository(AccountTransactions::class);
//if a new bid and its value is entered then prepare it for saving
if (!$auctionVehicleBid->getBiddingId() && $auctionVehicleBid->getBidValue()) {
$auctionVehicleBid->setBidder($vehicleClient);
$auctionVehicle->addAuctionVehicleBid($auctionVehicleBid);
$this->getDoctrine()->getManager()->persist($auctionVehicleBid);
$this->getDoctrine()->getManager()->flush($auctionVehicleBid);
$transactionsRepo->createAucSecTrans($auctionVehicleBid, $user, $user);
}
//if a new bid but no bid value entered then remove the bid object
elseif (!$auctionVehicleBid->getBiddingId() && !$auctionVehicleBid->getBidValue()) {
$auctionVehicleBid->setAuctionVehicle(null);
$auctionVehicle->removeAuctionVehicleBid($auctionVehicleBid);
}
//if an existing bid but no bid value entered then remove the bid from DB
elseif ($auctionVehicleBid->getBiddingId() && !$auctionVehicleBid->getBidValue()) {
//unlock the auction security locking transaction and update user locked security amount
$transactionsRepo->deleteBidTrans($auctionVehicleBid->getAuctionSecTransaction(), $this->getUser());
$this->getDoctrine()->getManager()->remove($auctionVehicleBid);
$this->getDoctrine()->getManager()->flush($auctionVehicleBid);
}
//if none of the above, then it is a existing bid value editing operation
else {
$this->getDoctrine()->getManager()->flush($auctionVehicleBid);
}
//[1.3] calculate unrestricted funds after applying user bids
$balance = (float)$user->getBalance();
$lockedOtSec = $user->getLockedOtSecurity();
$balanceAfterAction = $balance -$lockedOtSec;
//[1.4] decide whether rollback or commit changes
if ($balanceAfterAction > 0
&&
($balance < 0 || $lockedOtSec < 0 ) ) {
//[1.4.1] prevent either negative balance or negative security locks even if valid remaining funds. This odd case
//might happen due to wrong balance or wrong security locks from the begining
$session->getFlashBag()->add('warning',
$translator->trans('error! balance cant be negative', array(), 'clients')
);
$em->getConnection()->rollBack();
} elseif ( $balanceAfterAction < 0 ) {
//[1.4.2] the balance funds doesn't cover the requested action transactions
$session->getFlashBag()->add('warning',
$translator->trans('balance is less than the transaction with this amount', array('%{amount}'=> abs($balanceAfterAction) ), 'clients')
);
$em->getConnection()->rollBack();
} else {
//[1.4.3] if no errors then commit changes to DB
$session->getFlashBag()->add('success',
$translator->trans('bids have been saved successfully', array(), 'clients')
);
$em->getConnection()->commit();
}
}
return $this->render('default/vehicle_details.html.twig', array(
'vehicle' => $vehicle,
'locale' => $locale,
'imageRealPath' => $imageRealPath,
'bidForm' => $bidForm->createView()
));
}
/**
* @param Request $request
* @return mixed
* @throws \Doctrine\ORM\NonUniqueResultException
*/
private function getOngoingAuctionVehicles(Request $request, PaginatorInterface $paginator)
{
$em = $this->getDoctrine()->getManager();
$locale = $request->getLocale();
$vehicleHelper = new VehicleHelper();
$searchForm = $this->createFormBuilder()
->setMethod('GET')
->add('maker', EntityType::class, array(
'class' => VehicleMakers::class,
'label' => 'Vehicle Maker',
'choice_label' => 'name' . ucfirst($locale),
'placeholder' => 'Please Select',
'required' => false,
'translation_domain' => 'vehicles'
))
->add('model', EntityType::class, array(
'required' => false,
'label' => 'Vehicle Model',
'class' => VehicleModels::class,
'choice_label' => 'name' . ucfirst($locale),
'placeholder' => 'Please Select',
'attr' => array('disabled' => 'disabled'),
'translation_domain' => 'vehicles'
))
->add('manufacturingYear', ChoiceType::class, array(
'required' => false,
'label' => 'Made Year',
'choices' => $vehicleHelper->getYears(1990),
'placeholder' => 'Please Select',
'translation_domain' => 'vehicles'
))
->getForm();
$searchForm->handleRequest($request);
//$ongoingAuction = $em->getRepository(Auctions::class)->getOngoingAuction();
$repository = $em->getRepository(Auctions::class);
//get the ongoing auction. If multiple auctions, only the last one will be returned
$qb = $repository->createQueryBuilder('Auc')
->orderBy('Auc.auctionId', 'DESC')
->setMaxResults(1);
$ongoingAuction = $qb->getQuery()->getOneOrNullResult();
if ($ongoingAuction->getStatus() != Auctions::AUCTION_STATUSES['upcomming']) {
$auctionId = $ongoingAuction->getAuctionId();
$repository = $em->getRepository(Vehicles::class);
$qb = $repository->createQueryBuilder('V');
$qb->select('V', 'VR', 'AV.lineNumber');
$qb->join(AuctionVehicles::class, 'AV', 'with', 'V.vehicleId = AV.vehicle AND AV.auction = ' . $auctionId);
$qb->leftJoin('V.vehicleRegistrations', 'VR');
//if search fields submitted then filter result accordingly
if ($searchForm->isSubmitted()) {
$qb->where('1=1'); //workaround! just initializing the where clause with an always-true condition to freely use andWhere() inside if-else statements regardless of which condition will be true
if ($vehicleMaker = $searchForm->get('maker')->getData()) {
if ($vehicleModel = $searchForm->get('model')->getData()) {
$qb->andWhere('VR.model = :vehicleModel')
->setParameter('vehicleModel', $vehicleModel);
} else {
$modelsRepo = $this->getDoctrine()
->getRepository(VehicleModels::class);
$modelsQuery = $modelsRepo->createQueryBuilder('m')
->select('m.modelId')
->where('m.maker = :makerID')
->setParameter('makerID', $vehicleMaker)
->getQuery();
$makerModels = $modelsQuery->getArrayResult();
foreach ($makerModels as $maker) {
$makerModelsArr[] = $maker['modelId'];
}
$qb->andWhere('VR.model IN (:makerModels)')
->setParameter('makerModels', $makerModelsArr);
}
}
if ($manufacturingYear = $searchForm->get('manufacturingYear')->getData()) {
$qb->andWhere('VR.manufacturingYear = :manufacturingYear')
->setParameter('manufacturingYear', $manufacturingYear);
}
}
$qb->orderBy('AV.lineNumber', 'ASC');
$auctionVehicles = $qb->getQuery()->getResult();
$totalResult = count($auctionVehicles);
$auctionVehicles = $paginator->paginate(
$auctionVehicles,
$request->query->getInt('page', 1),
$request->query->getInt('limit', 20)
);
} else {
$auctionVehicles = null;
$totalResult = 0;
$paginator = null;
}
$imageRealPath = $this->getParameter('vehicle_uploaded_files') . '/';
$data['searchForm'] = $searchForm;
$data['locale'] = $locale;
$data['auctionVehicles'] = $auctionVehicles;
$data['totalResult'] = $totalResult;
$data['paginator'] = $paginator;
$data['imageRealPath'] = $imageRealPath;
$data['auctionStatus'] = $ongoingAuction->getStatus();
$data['auction'] = $ongoingAuction;
$data['endDate'] = ($ongoingAuction &&$ongoingAuction->getEndDate()) ?$ongoingAuction->getEndDate() : false;
return $data;
}
}