src/Service/OdSeoService.php line 121

Open in your IDE?
  1. <?php
  2. /**
  3.  * User: remmel
  4.  * Date: 1/4/16
  5.  * Time: 12:45 AM
  6.  */
  7. namespace App\Service;
  8. use App\Controller\Frontend\SeoOd;
  9. use App\Controller\Frontend\Thumbnail;
  10. use App\Entity\Block;
  11. use App\Entity\model\Conveyance;
  12. use App\Entity\model\RouteSeo;
  13. use App\Entity\model\StatPriceDuration;
  14. use App\Entity\PictureStop;
  15. use App\Entity\Price;
  16. use App\Entity\Stop;
  17. use App\Entity\StopLang;
  18. use App\Extension\LocaleListener;
  19. use App\Repository\BlockRepository;
  20. use App\Repository\PictureStopRepository;
  21. use App\Repository\PriceRepository;
  22. use App\Repository\StationRepository;
  23. use App\Repository\StopLangRepository;
  24. use App\Repository\StopRepository;
  25. use App\Service\Client\ClientRepository;
  26. use App\Utils\StringUtils;
  27. use App\Utils\Utils;
  28. use Doctrine\ORM\EntityManagerInterface;
  29. use Symfony\Component\Cache\Adapter\ApcuAdapter;
  30. use Symfony\Contracts\Cache\ItemInterface;
  31. use Symfony\Contracts\Translation\TranslatorInterface;
  32. /**
  33.  * Added as service in services.yml (also can be set as service in Route(service="app.base_controller") in next Symfony version)
  34.  */
  35. class OdSeoService
  36. {
  37.     const TRANS_IDS = [
  38.         'train' => ['trip.1''trip.2''trip.3''trip.4''trip.5''trip.6''trip.reverse''trip.list''trip.list.address''trip.list.companies''trip.list.schedule''address.dep.one''address.dep.multi''address.arr.one''address.arr.multi''schedule.1''schedule.2''a.1''a.2''b.1''b.2''c.1''c.2''d.1''d.2''e.1''e.2''f.1''f.2''g.1''g.2''h.1','h.2'],
  39.         'bus'   => ['trip.1''trip.2''trip.3''trip.4''trip.5''trip.6''trip.reverse''trip.list''trip.list.address''trip.list.companies''trip.list.schedule''address.dep.multi''address.dep.one''address.arr.multi''address.arr.one''schedule.1''schedule.2''a.1''a.2''b.1''b.2''c.1''c.2''d.1''d.2']
  40.     ];
  41.     private UrlRewrite $urlRewriteService;
  42.     private LabelBuilder $labelBuilder;
  43.     private TranslatorInterface $translator;
  44.     private CurrencyService $currencyService;
  45.     private ClientRepository $clientRepo;
  46.     protected EntityManagerInterface $em;
  47.     protected string $projectDir;
  48.     protected StationRepository $stationRepository;
  49.     // https://docs.google.com/spreadsheets/d/148-fwmN3X-mHVoAs2crSos-B2Vf6UcwPxkuK0bCqZa8/edit#gid=1807861344
  50.     protected array $seoroutes;
  51.     public function __construct(string $seoRoutesFilenameCurrencyService $currencyServiceUrlRewrite $urlRewriteServiceLabelBuilder $labelBuilderTranslatorInterface $translatorClientRepository $clientRepoEntityManagerInterface $emstring $projectDirStationRepository $stationRepository) {
  52.         $this->currencyService $currencyService;
  53.         $this->urlRewriteService $urlRewriteService;
  54.         $this->labelBuilder $labelBuilder;
  55.         $this->translator $translator;
  56.         $this->clientRepo $clientRepo;
  57.         $this->em $em;
  58.         $this->projectDir $projectDir;
  59.         $this->stationRepository $stationRepository;
  60.         $apcu = new ApcuAdapter(); //FIXME used inject one, when cache usage properly configured
  61.         $this->seoroutes $apcu->get('seoroutes', function (ItemInterface $item) use ($seoRoutesFilename) {
  62.             return Utils::file_get_contents_csv_header($seoRoutesFilename);
  63.         });
  64.     }
  65.     private function getPriceRepo(): PriceRepository {
  66.         return $this->em->getRepository(Price::class);
  67.     }
  68.     private function getStopLangRepo(): StopLangRepository {
  69.         return $this->em->getRepository(StopLang::class);
  70.     }
  71.     private function getBlockRepo(): BlockRepository {
  72.         return $this->em->getRepository(Block::class);
  73.     }
  74.     private function getStopRepo(): StopRepository {
  75.         return $this->em->getRepository(Stop::class);
  76.     }
  77.     private function getPrictureStopRepo(): PictureStopRepository {
  78.         return $this->em->getRepository(PictureStop::class);
  79.     }
  80.     private function isFrenchRoute(Stop $depStopStop $arrStop): bool {
  81.         return ($depStop->getCountry() === 'FR' && $arrStop->getCountry() === 'FR');
  82.     }
  83.     private function getThumbnailOD(Stop $depStopStop $arrStopstring $conveyance): ?Thumbnail {
  84.         $relativePath '/bundles/static/uploads/Trajets/';
  85.         $absolutePath $this->projectDir.'/public'.$relativePath//getcwd doesn't work in test
  86.         $img $this->labelBuilder->translatesThumbnail($depStop->getName(), $arrStop->getName(), $conveyance);
  87.         if(file_exists($absolutePath.$img->filename)) {
  88.             $img->src $relativePath.$img->filename;
  89.             return $img;
  90.         } else {
  91.             return null;
  92.         }
  93.     }
  94.     /**
  95.      * Content displayed on the indexed page
  96.      * 3 cases :
  97.      * - not indexed (has date)
  98.      * - indexed but no stats
  99.      * - has stats
  100.      * TODO makes calculation for other currency
  101.      * TODO extract that in a seoService
  102.      */
  103.     public function getSeoOd(Stop $depStopStop $arrStopstring $transportbool $noIndexstring $_locale): SeoOd {
  104.         $seoOd = new SeoOd();
  105.         //TODO call that method only if index?
  106.         if(!$noIndex && $transport !== Conveyance::ALL) {
  107.             $seoOd->currency $currency $this->labelBuilder->getTransCurrency();
  108.             //1) stat & cheapest
  109.             $seoOd->stat $this->getStat($depStop$arrStop$transport$currency);
  110.             if($seoOd->stat) {
  111.                 $seoOd->cheapest round($seoOd->stat->getPriceMin() / 100);
  112.             }
  113.             //2) prices
  114.             if($transport === Conveyance::TRAIN || $transport === Conveyance::BUS) {
  115.                 $seoOd->prices $this->getPriceRepo()->findLastPriceByStops($depStop->getId(), $arrStop->getId(), $transport);
  116.             }
  117.             foreach ($seoOd->prices as $p) {
  118.                 if (empty($p->getCompanyName())) {
  119.                     $companyName $this->clientRepo->find($p->getCompanyId())->getName();
  120.                     $p->setCompanyName($companyName);
  121.                     $this->currencyService
  122.                         ->updateCurrency($p$currency);
  123.                 }
  124.             }
  125.             //3) img
  126.             $seoOd->img $this->getThumbnailOD($depStop$arrStop$transport);
  127.             //block
  128.             $seoOd->block $this->getRouteBlock($depStop$arrStop$_locale$transport);
  129.             //return link in automated text
  130.             if($this->isFrenchRoute($arrStop$depStop)) {
  131.                 $seoOd->returnLink $this->urlRewriteService->createRouteLink($arrStop$depStopfalse$transport);
  132.             }
  133.             // stations addresses
  134.             $seoOd->depAddresses $this->stationRepository->find($transport$depStop->getId());
  135.             $seoOd->arrAddresses $this->stationRepository->find($transport$arrStop->getId());
  136.             //no automated text for flight and carpooling
  137.             if ($transport === Conveyance::TRAIN || $transport === Conveyance::BUS) {
  138.                 $seoOd->transIds $this->labelBuilder->generatesTransIds($depStop->getId() + $arrStop->getId() * 5self::TRANS_IDS[$transport], 3);
  139.             }
  140.             //FIXME quickfix to avoid calling costing findCarrier on everypage (only index and cached page)
  141.             $connection $transport === Conveyance::FLIGHT false;
  142.             $carriersName $this->getPriceRepo()->findCarriers($depStop->getId(), $arrStop->getId(), $connection$transport);
  143.             $seoOd->companiesName $this->labelBuilder->createCompanyName($carriersName$transport);
  144. //            $seoOd->alternateConvenyanceRoutes = $this->getAlternateRoutesFromCsv($depStop, $arrStop, $transport, $_locale);
  145.         }
  146.         //add companies automated text
  147.         //could directly do that in view, but we need to know before if we have carries to display
  148.         if (count($seoOd->transIds)) { //only if automated text
  149.             $ids self::TRANS_IDS[$transport];
  150.             $lastKey end($ids);
  151.             $lastLetter explode('.'$lastKey)[0];
  152.             foreach (range('a'$lastLetter) as $c) {
  153.                 $companyName $this->translator->trans("$transport.odpage.spinning.$c.name");
  154.                 if (in_array($companyName$seoOd->companiesName)) { //could ignore cases
  155.                     $seoOd->companiesLetter[] = $c;
  156.                 }
  157.             }
  158.         }
  159.         $country $this->labelBuilder->getTransCountry();
  160.         $seoOd->distanceMi round($depStop->distance($arrStop'N'));
  161.         $seoOd->distanceKm round($depStop->distance($arrStop));
  162.         if(in_array($country, ['GB''US']))
  163.             $seoOd->distanceNice $seoOd->distanceMi.' mi';
  164.         else
  165.             $seoOd->distanceNice $seoOd->distanceKm.' km';
  166.         $seoOd->transParams $this->createsTransODParams($depStop$arrStop$seoOd$_locale);
  167.         return $seoOd;
  168.     }
  169.     public function createsTransODParams(Stop $depStopStop $arrStopSeoOd $seoOdstring $locale): array {
  170.         $params = [
  171.             '%A%' => $depStop->getName(),
  172.             '%B%' => $arrStop->getName(),
  173.             '%KM%' => round($seoOd->distanceKm),
  174.             '%MI%' => round($seoOd->distanceMi),
  175.             '%DISTANCE%' => $seoOd->distanceNice,
  176.             '%COMPANIES%' => $this->labelBuilder->joinTexts($seoOd->companiesName),
  177.         ];
  178.         if($seoOd->stat) {
  179.             $params array_merge($params, [
  180.                 '%PRICE%' => CurrencyService::nicePrice($seoOd->stat->getPriceMin(), $seoOd->currency$locale),
  181.                 '%PRICE_MIN%' => CurrencyService::nicePrice($seoOd->stat->getPriceMin(), $seoOd->currency$locale),
  182.                 '%PRICE_AVG%' => CurrencyService::nicePrice($seoOd->stat->getPriceAvg(), $seoOd->currency$locale),
  183.                 '%PRICE_MAX%' => CurrencyService::nicePrice($seoOd->stat->getPriceMax(), $seoOd->currency$locale),
  184.                 '%EUR%' => round($seoOd->stat->getPriceMin() / 100),
  185.                 '%DUR_AVG%' => $this->labelBuilder->niceDuration($seoOd->stat->getDurationAvg()),
  186.                 '%DUR_MIN%' => $this->labelBuilder->niceduration($seoOd->stat->getDurationMin()),
  187.                 '%DUR_MAX%' => $this->labelBuilder->niceduration($seoOd->stat->getDurationMax()),
  188.             ]);
  189.         }
  190.         return $params;
  191.     }
  192.     protected function getStat(Stop $depStopStop $arrStopstring $transportstring $currency): ?StatPriceDuration {
  193.         $stat $this->getStatDaysOld($depStop$arrStop$transport$currencyfalse);
  194.         if(!$stat)
  195.             $stat $this->getStatDaysOld($depStop$arrStop$transport$currencytrue);
  196.         return $stat;
  197.     }
  198.     protected function getStatDaysOld(Stop $depStopStop $arrStopstring $transportstring $currencybool $lookfurther): ?StatPriceDuration {
  199.         $createdDaysOld $lookfurther 30 7;
  200.         // get direct trip only when flight AND not lookfurther. I guess this can be simplifed, that not really what we want now
  201.         $connection $transport == Conveyance::FLIGHT && !$lookfurther false;
  202.         $currenciesUsed $this->getPriceRepo()
  203.             ->findRouteCurrency($depStop->getId(), $arrStop->getId(), $transport$createdDaysOld);
  204.         $currenciesWithRates = [
  205.             $currency => 1
  206.         ];
  207.         foreach ($currenciesUsed as $c)
  208.             $currenciesWithRates[$c] = $this->currencyService->getRate($c$currency);
  209.         return $this->getPriceRepo()
  210.             ->findRouteStat($depStop->getId(), $arrStop->getId(), $transport$currenciesWithRates$createdDaysOld$connection);
  211.     }
  212.     protected function getRouteBlock(Stop $depStop $arrstring $_localestring $conveyance): Block {
  213.         $path '';
  214.         $ids $dep->getId().'-'.$arr->getId();
  215.         switch ($conveyance) {
  216.             case Conveyance::BUS:
  217.                 $path "/$_locale/bus-o-d-$ids"; break;
  218.             case Conveyance::TRAIN:
  219.                 $path "/$_locale/train/o-d-$ids"; break;
  220.             case Conveyance::FLIGHT:
  221.                 $path "/$_locale/avion/o-d-$ids"; break;
  222.             case Conveyance::CARPOOLING:
  223.                 $path "/$_locale/covoiturage/o-d-$ids"; break;
  224.         }
  225.         $b $this->getBlockRepo()->findOnebyPathNotNull($path);
  226.         if($b->getContent())
  227.             $b->setContent(str_replace('%MAP%'self::createMap($dep$arr), $b->getContent()));
  228.         return $b;
  229.     }
  230.     /** @return RouteSeo[] */
  231.     public function getPopularRoutesFromCsv(Stop $depstring $transportationstring $_locale) :array{
  232.         $routes = [];
  233.         foreach ($this->seoroutes as $r) {
  234.             if($r->locale === $_locale && $r->type === $transportation && (int)$r->dep_stop_id === $dep->getId()) {
  235.                 $arr $this->getStopRepo()->findNotRemovedTranslated($r->arr_stop_idLocaleListener::getLang($_locale));
  236.                 $routes[] = RouteSeo::createFromStops($dep$arr);
  237.             }
  238.         }
  239.         return $routes;
  240.     }
  241. //    /**
  242. //     * @return Link[]
  243. //     */
  244. //    public function getAlternateRoutesFromCsv(Stop $dep, Stop $arr, string $transportation, string $_locale) :array{
  245. //        $routes = [];
  246. //        foreach ($this->seoroutes as $r) {
  247. //            if($r->locale === $_locale && $r->type !== $transportation && (int)$r->dep_stop_id === $dep->getId() && (int)$r->arr_stop_id === $arr->getId()) {
  248. //                $routes[] = RouteSeo::createFromStops($dep, $arr);
  249. //            }
  250. //        }
  251. //        return $this->urlRewriteService->createRoutesLink($routes);
  252. //    }
  253.     public function getInfoStop(string $stopIdstring $transportstring $_locale): array {
  254.         $block $this->getBlockRepo()->findOnebyPathNotNull("/$_locale/$transport-o-d/destination/$stopId");
  255.         $pictures $this->getPrictureStopRepo()
  256.             ->findByStop($stopId);
  257.         return ['block' => $block'imgs' => $pictures];
  258.     }
  259.     /**
  260.      * Create OD map
  261.      */
  262.     public static function createMap(Stop $depStopStop $arrStop) :string{
  263.         $depGeo $depStop->getLonLatComma();
  264.         $arrGeo $arrStop->getLonLatComma();
  265.         return 'https://static-maps.yandex.ru/1.x/?lang=en_US&l=map&pt='.
  266.             "$depGeo,pm2lbm1" .
  267.             '~'.
  268.             "$arrGeo,pm2lbm2" .
  269.             '&size=300,300';
  270.     }
  271. }