src/Controller/Api/ApiPriceController.php line 66

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Api;
  3. use App\Entity\model\Conveyance;
  4. use App\Entity\Price;
  5. use App\Entity\StopExt;
  6. use App\Repository\PriceRepository;
  7. use App\Repository\StopExtRepository;
  8. use App\Service\Client\ClientRepository;
  9. use App\Service\Client\IClient;
  10. use App\Service\Client\Trip;
  11. use App\Service\CurrencyService;
  12. use App\Service\LabelBuilder;
  13. use App\Service\PriceService;
  14. use App\Service\UrlRewrite;
  15. use DateTime;
  16. use Doctrine\ORM\EntityManagerInterface;
  17. use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
  18. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  19. use Symfony\Component\HttpFoundation\JsonResponse;
  20. use Symfony\Component\Routing\Annotation\Route;
  21. /**
  22.  * @Route("/api", options={"i18n"=false})
  23.  */
  24. class ApiPriceController extends AbstractController {
  25.     private UrlRewrite $rewriteService;
  26.     private LabelBuilder $labelBuilder;
  27.     private ClientRepository $clientRepo;
  28.     private PriceService $priceService;
  29.     private CurrencyService $currencyService;
  30.     /** @required */
  31.     public function setServices(UrlRewrite $rewriteServiceLabelBuilder $labelBuilderClientRepository $clientRepoPriceService $priceServiceCurrencyService $currencyService) {
  32.         $this->rewriteService $rewriteService;
  33.         $this->labelBuilder $labelBuilder;
  34.         $this->clientRepo $clientRepo;
  35.         $this->priceService $priceService;
  36.         $this->currencyService $currencyService;
  37.     }
  38.     /**
  39.      * @Route("/prices", name="api_price_company")
  40.      * Recupere les prix du webservice ou depuis la bdd si deja existant
  41.      * 1-Les prix sont-ils en bdd? Oui=Fin
  42.      * 2-Récupération des prix depuis le scraper
  43.      * 3-Mise en bdd des prix
  44.      * 4-Return prix
  45.      * TODO delete level of outbound / inbound? requirements = {"companyId" = "1|2|3"}
  46.      * TODO send the response and after put in db ($response->send();)
  47.      * @ParamConverter("companyId", converter="querystring")
  48.      * @ParamConverter("stopExtDep", converter="querystring")
  49.      * @ParamConverter("stopExtArr", converter="querystring")
  50.      * @ParamConverter("stopIdDep", converter="querystring")
  51.      * @ParamConverter("stopIdArr", converter="querystring")
  52.      * @ParamConverter("dateFrom", converter="querystring")
  53.      * @ParamConverter("dateTo", converter="querystring")
  54.      * @ParamConverter("currency", converter="querystring")
  55.      * @ParamConverter("k", converter="querystring")
  56.      * @ParamConverter("forcenocache", converter="querystring")
  57.      * @ParamConverter("locale", converter="querystring")
  58.      */
  59.     public function pricesByCompanyAction(int $companyIdstring $stopExtDepstring $stopExtArrint $stopIdDepint $stopIdArrstring $dateFrom, ?string $dateTo nullstring $currencystring $k null, ?bool $forcenocache nullstring $locale,
  60.                                           PriceRepository $priceRepoStopExtRepository $stopExtRepoEntityManagerInterface $em) {
  61.         $isOneWay $dateTo == null;
  62.         $scraper $this->clientRepo->find($companyId);
  63.         //dirty code to backlist wrong use of the api - GET /api/prices?companyId=13&stopExtDep=2015&stopExtArr=1965&stopIdDep=6&stopIdArr=10&dateFrom=2018-11-08&dateTo=&currency=EUR
  64.         if (empty($k)) {
  65.             return $this->render("Default/error_api.html.twig");
  66.         }
  67.         //if the api is misused got cache price
  68.         $illegaluse $k !== 'cbapp_PaidApi' && $k !== 'apicb';
  69.         $depStopExt $stopExtRepo->findOneByCodeAndCompanyIdAndStopId($stopExtDep$companyId$stopIdDep);
  70.         $arrStopExt $stopExtRepo->findOneByCodeAndCompanyIdAndStopId($stopExtArr$companyId$stopIdArr);
  71.         //if our IP is misused, and the depStopId / arrStopId are wrong
  72.         if ($depStopExt === null || $arrStopExt === null) {
  73.             $depStopExt $stopExtRepo->findOneByCodeAndCompanyId($stopExtDep$companyId);
  74.             $arrStopExt $stopExtRepo->findOneByCodeAndCompanyId($stopExtArr$companyId);
  75.         }
  76.         //stopExt not found because for example none (eg BBC)
  77.         if ($depStopExt === null || $arrStopExt === null) {
  78.             $depStopExt StopExt::withParms($stopExtDep$companyId$stopIdDep);
  79.             $arrStopExt StopExt::withParms($stopExtArr$companyId$stopIdArr);
  80.         }
  81.         $cached = !$forcenocache && $scraper->isCached();
  82.         $response = new ApiPriceResponse();
  83.         $response->debug 'data_dbcache';
  84.         if ($illegaluse) { //only dislay cache price
  85.             $response->outbound $this->priceService->getDbPrice($depStopExt$arrStopExt$dateFrom24 10);
  86.             $response->inbound = [];
  87.             $cached true;
  88.             $response->debug 'data_fresh_';
  89.             if ($response->outbound == null$response->outbound = [];
  90.             foreach ($response->outbound as $p) {
  91.                 $p->setCreatedAt(new DateTime());
  92.             }
  93.         } else if ($cached) {
  94.             $expiration self::getExpirationHours($scraper->getCacheHours(), $dateFrom);
  95.             $response->outbound $this->priceService->getDbPrice($depStopExt$arrStopExt$dateFrom$expiration);
  96.             if (!$isOneWay) {
  97.                 $expiration self::getExpirationHours($scraper->getCacheHours(), $dateTo);
  98.                 $response->inbound $this->priceService->getDbPrice($arrStopExt$depStopExt$dateTo$expiration);
  99.             }
  100.         }
  101.         // Scrapper will be run if no inbound or outbound price but no item this day (item empty storing that we already fetch that day but there is no trip
  102.         if (!$cached || $response->outbound === null || $response->inbound === null) {
  103.             $response->debug 'data_fresh';
  104. //            $this->get('logger')->info("fetch from scrapper");
  105.             $trips $scraper->getPrice($stopExtDep$stopExtArr$dateFrom$dateTo);
  106.             if ($cached) {
  107.                 //delete old price. Handle multiday and one day
  108.                 $priceRepo->deletePriceByStopExt($depStopExt$arrStopExt$dateFrom);
  109.                 if (!$isOneWay) {
  110.                     $priceRepo->deletePriceByStopExt($arrStopExt$depStopExt$dateTo);
  111.                 }
  112.             }
  113.             $response->outbound = []; //because it's out OR in not empty
  114.             $response->inbound = [];
  115.             //met en bdd
  116.             foreach ($trips as $t) {
  117.                 $p Price::createPriceFromTrip($depStopExt$arrStopExt$t);
  118.                 PriceService::useReference($p$em);
  119.                 if ($cached) {
  120.                     $em->persist($p);
  121.                 }
  122.                 //Add to outbound if outbound and date == $from/dep
  123.                 if ($t->getDirection() == Trip::OUTBOUND) { //FIXME sometime direction is null (no ===), replace with boolean?
  124.                     $response->outbound[] = $p;
  125.                 }
  126.                 //Add to outbound if inbound and date == $to/dep
  127.                 if ($t->getDirection() == Trip::INBOUND) {
  128.                     $response->inbound[] = $p;
  129.                 }
  130.             }
  131.             //store that price has been scrapped but no trip that day
  132.             if ($cached && count($response->outbound) === 0) {
  133.                 $p Price::createNoTrip($depStopExt$arrStopExt$dateFrom);
  134.                 PriceService::useReference($p$em);
  135.                 $em->persist($p);
  136.             }
  137.             if (!$isOneWay && count($response->inbound) == && $cached) {
  138.                 $p Price::createNoTrip($arrStopExt$depStopExt$dateTo);
  139.                 PriceService::useReference($p$em);
  140.                 $em->persist($p);
  141.             }
  142.             $em->flush();
  143.             $this->fillStopNameList($response->outbound$depStopExt$arrStopExt);
  144.             $this->fillStopNameList($response->inbound$arrStopExt$depStopExt);
  145.         }
  146.         //cors = true : is also called from www.cb.com -> demo.cb.com
  147.         return $this->responseJsonFromApiResponse($response$currencytrue$scraper$locale);
  148.     }
  149.     /**
  150.      * The cache is changed depending of the proximity of the trip
  151.      */
  152.     public static function getExpirationHours(int $normalExpirationHoursstring $date, \DateTime $today null) : float {
  153.         $today $today??new DateTime();
  154.         $today->setTime(000);
  155.         $match_date DateTime::createFromFormat('Y-m-d'$date);
  156.         $match_date->setTime(000);
  157.         $diff $today->diff($match_date);
  158.         $diffDays = (integer)$diff->format('%R%a'); // days before departure
  159.         switch ($diffDays) {
  160.             case -1//maybe can happen if searching in America, server time is already the day after
  161.             case 0//today
  162.                 return $normalExpirationHours 8;
  163.             case 1//tomorrow
  164.                 return $normalExpirationHours 4// 2hrs
  165.             case 2//2 days
  166.                 return $normalExpirationHours 2// 4hrs
  167.         }
  168.         return $normalExpirationHours;
  169.     }
  170.     protected function responseJsonFromApiResponse(ApiPriceResponse $resstring $currencybool $corsIClient $scraperstring $locale) {
  171.         $header = [];
  172.         if ($cors) {
  173.             $header['Access-Control-Allow-Origin'] = 'https://www.comparabus.com';
  174.         }
  175.         return new JsonResponse([
  176.             'debug' => $res->debug,
  177.             'inbound' => $this->convertPricesToApi($res->inbound$currency$scraper$locale),
  178.             'outbound' => $this->convertPricesToApi($res->outbound$currency$scraper$locale),
  179.         ], 200$header);
  180.     }
  181.     protected function convertPricesToApi(array $pricesstring $currencyIClient $scraperstring $locale) {
  182.         $apiPrices = [];
  183.         foreach ($prices as $p)
  184.             $apiPrices[] = $this->convertPriceToApi($p$currency$scraper$locale);
  185.         return $apiPrices;
  186.     }
  187.     protected function convertPriceToApi(Price $pstring $toCurrencyIClient $companystring $locale): array {
  188.         //takes type from Price otherwise takes type from Company
  189.         //TODO type must always be fixed
  190.         $conveyance $p->getType() === null $company->getType() : Conveyance::fromPriceType($p->getType());
  191. //        if ($conveyance == Conveyance::FLIGHT) {
  192. //            $infos = $p->getInfo();
  193. //            foreach ($infos as &$info) {
  194. //                $cents = $this->currencyService->updateCurrencyInfo($info['cents'], $p->getCurrency(), $toCurrency);
  195. //                $info['price'] = CurrencyService::nicePrice($cents, $toCurrency, $locale);
  196. //            }
  197. //            $p->setInfo($infos);
  198. //        }
  199.         if ($p->getCents() > 0) {
  200.             $this->currencyService->updateCurrency($p$toCurrency);
  201.         }
  202.         return [
  203.             'createdAt' => $p->getCreatedAt()->format('Y-m-d H:i:s'),
  204.             'companyId' => $p->getCompanyId(),
  205.             'companyName' => $company->getName(),
  206.             'type' => $conveyance,
  207.             'stopExtDep' => $p->getStopExtDep(),
  208.             'stopExtArr' => $p->getStopExtArr(),
  209.             'cents' => $p->getCents(),
  210.             'currency' => $p->getCurrency(),
  211.             'price' => $p->getCents() ? CurrencyService::nicePrice($p->getCents(), $p->getCurrency(), $locale) : null,
  212.             'duration' => $p->getDuration(),
  213.             'depDatetime' => $p->getDepDatetime()->format('Y-m-d H:i:s'),
  214.             'arrDatetime' => $p->getArrDatetime()->format('Y-m-d H:i:s'),
  215.             'link' => $p->getLink(),
  216.             'full' => $p->getFull(),
  217.             'stopNameDep' => $p->getStopNameDep(),
  218.             'stopNameArr' => $p->getStopNameArr(),
  219.             'carrierName' => $p->getCarrierName(),
  220.             'carrierCode' => $p->getCarrierCode(),
  221.             'connection' => $p->getConnection(),
  222.             'id' => $p->getId(),
  223.             'stopIdDep' => $p->getDepStop()->getId(),
  224.             'stopIdArr' => $p->getArrStop()->getId(),
  225.             'info' => $p->getInfo()
  226.         ];
  227.     }
  228.     /**
  229.      * @param Price[] $prices
  230.      */
  231.     private function fillStopNameList(array $pricesStopExt $depStopStopExt $arrStop): void {
  232.         foreach ($prices as $p) {
  233.             $p->fillStopNameIfEmpty($depStop$arrStop);
  234.         }
  235.     }
  236. }