src/Service/FacilityService.php line 294

Open in your IDE?
  1. <?php
  2. /**
  3.  * Created by Elements.at New Media Solutions GmbH
  4.  *
  5.  */
  6. namespace App\Service;
  7. use Carbon\Carbon;
  8. use Elements\Bundle\SeoHelperBundle\Service\PrettyUrl;
  9. use Exception;
  10. use GuzzleHttp\Client;
  11. use GuzzleHttp\Exception\GuzzleException;
  12. use Pimcore\Cache;
  13. use Pimcore\Model\DataObject;
  14. use Pimcore\Model\DataObject\Lift;
  15. use Pimcore\Model\DataObject\Listing\Concrete;
  16. use Pimcore\Model\DataObject\Miscellaneous;
  17. use Pimcore\Model\DataObject\Resort;
  18. use Pimcore\Model\DataObject\Slope;
  19. use Pimcore\Model\Document\Editable;
  20. use Pimcore\Translation\Translator;
  21. class FacilityService
  22. {
  23.     const NO_INFORMATION 0;
  24.     const OPEN 1;
  25.     const IN_PREPARATION 2;
  26.     const CLOSED_TECHNICAL 3;
  27.     const CLOSED_OPERATIONAL 5;
  28.     const CLOSED_ATMOSPHERIC 6;
  29.     const OUT_OF_ORDER 7;
  30.     const SLOPE_OPEN 8;
  31.     const SLOPE_IN_PREPARATION 9;
  32.     const SLOPE_CLOSED_AVALANCHE 10;
  33.     const SLOPE_CLOSED_ICE 11;
  34.     const SLOPE_CLOSED_WIND 12;
  35.     const SLOPE_CLOSED_STORM 13;
  36.     const SLOPE_OUT_OF_ORDER 14;
  37.     const SLOPE_CLOSED 15;
  38.     const CLOSED 16;
  39.     const DAY_OF_REST 17;
  40.     const COMPANY_VACATION 18;
  41.     public const INFOSNOW_URL 'https://infosnow.zbag.ch/?type=xml&id=16&report=93&ref=afed710d1d79f879e110247c8051d83a';
  42.     public const LIFETIME 180;
  43.     public function __construct(
  44.         protected PrettyUrl $prettyUrl,
  45.         protected FormService $formService,
  46.         protected Client $client,
  47.         protected Translator $translator
  48.     ) {
  49.     }
  50.     /**
  51.      * @param Editable|null $resortRelations
  52.      *
  53.      * @return array<mixed>
  54.      */
  55.     public function getResortTabs(Editable $resortRelations null, ?string $date null, ?string $language 'de'): array
  56.     {
  57.         $listing = new Resort\Listing();
  58.         $resorts $resortRelations && !$resortRelations->isEmpty() && method_exists($resortRelations'getElements') ? $resortRelations->getElements() : $listing->load();
  59.         return array_map(function ($r) use ($resorts$date$language) {
  60.             return [
  61.                 'text' => $r->getName(),
  62.                 'id' => $r->getId(),
  63.                 'targetId' => 'tab-' $r->getId(),
  64.                 'isActive' => $r->getId() == $resorts[0]->getId(),
  65.                 'contentUrl' => $this->prettyUrl->prettyUrl([ 'tab' => $r->getId(), 'date' => $date ], 'facility_tab'),
  66.                 'warnings' => $this->getInfoSnowWarnings($language$r->getInfosnowId()),
  67.             ];
  68.         }, $resorts);
  69.     }
  70.     /**
  71.      * @param string $language
  72.      * @param bool $disableCache
  73.      *
  74.      * @return array<mixed>|null
  75.      */
  76.     public function getAllInfoSnowWarnings(string $language 'de'bool $disableCache false): ?array
  77.     {
  78.         $data null;
  79.         $messageCacheKey md5(($language 'overviewData'));
  80.         if(!$disableCache) {
  81.             $data Cache::load($messageCacheKey);
  82.         }
  83.         if (!$data) {
  84.             $tmpData $this->getCachedData(self::INFOSNOW_URLself::LIFETIME$disableCache);
  85.             try {
  86.                 $data = [];
  87.                 $languageMapping = ['de' => 1'fr' => 2'en' => 3'it' => 4];
  88.                 $xml simplexml_load_string($tmpData);
  89.                 $items $xml->xpath('/Export/ticker/program');
  90.                 foreach ($items as $item) {
  91.                     $regions null;
  92.                     foreach ($item->xpath('sectors/sector') as $region) {
  93.                         $regions[] = (string)$region->sector;
  94.                     }
  95.                     $tmpAggData null;
  96.                     foreach ($item->xpath('text') as $text) {
  97.                         if ((int)$text->attributes()->lang === $languageMapping[$language]) {
  98.                             $tmpAggData[] = (string)$text;
  99.                         }
  100.                     }
  101.                     $title null;
  102.                     if (!is_array($regions)) {
  103.                         $regions = ['general'];
  104.                         $title $this->translator->trans('infosnow.general.title');
  105.                     }
  106.                     foreach ($regions as $region) {
  107.                         $key hash('sha256'$region);
  108.                         $newContent $tmpAggData;
  109.                         if (array_key_exists($key$data) && array_key_exists('items'$data[$key])) {
  110.                             $newContent array_merge($data[$key]['items'], $tmpAggData);
  111.                         }
  112.                         $data[$key]['title'] = $title ?? $region;
  113.                         $data[$key]['items'] = $newContent;
  114.                     }
  115.                 }
  116.             } catch (Exception $exception) {
  117.             }
  118.             Cache::save(
  119.                 $data,
  120.                 $messageCacheKey,
  121.                 ['resortData''warnings'],
  122.                 self::LIFETIME
  123.             );
  124.         }
  125.         return $data;
  126.     }
  127.     /**
  128.      * @param string $language
  129.      * @param int|null $resortId
  130.      * @param bool $disableCache
  131.      *
  132.      * @return array<mixed>|null
  133.      */
  134.     public function getInfoSnowWarnings(string $language 'de', ?int $resortId nullbool $disableCache false): ?array
  135.     {
  136.         $data null;
  137.         $messageCacheKey md5(($language $resortId));
  138.         if(!$disableCache) {
  139.             $data Cache::load($messageCacheKey);
  140.         }
  141.         if (!$data) {
  142.             $tmpData $this->getCachedData(self::INFOSNOW_URLself::LIFETIME$disableCache);
  143.             $data $this->aggregateData($tmpData$language$resortId);
  144.             Cache::save(
  145.                 $data,
  146.                 $messageCacheKey,
  147.                 ['resortData''warnings'],
  148.                 self::LIFETIME
  149.             );
  150.         }
  151.         return $data;
  152.     }
  153.     public function hasInfoSnowWarnings(): bool
  154.     {
  155.         $tmpData $this->getCachedData(self::INFOSNOW_URLself::LIFETIME);
  156.         $xml simplexml_load_string($tmpData);
  157.         $items $xml->xpath('/Export/ticker/program');
  158.         return !empty($items);
  159.     }
  160.     /**
  161.      * @param string $tmpData
  162.      * @param string $language
  163.      * @param int|null $resortId
  164.      *
  165.      * @return array<mixed>
  166.      */
  167.     public function aggregateData(string $tmpDatastring $language, ?int $resortId): array
  168.     {
  169.         try {
  170.             $data = [];
  171.             $languageMapping = ['de' => 1'fr' => 2'en' => 3'it' => 4];
  172.             $xml simplexml_load_string($tmpData);
  173.             $items $xml->xpath('/Export/ticker/program');
  174.             foreach ($items as $item) {
  175.                 $additionalTitle null;
  176.                 try {
  177.                     if (null !== $resortId) {
  178.                         foreach ($item->xpath('sectors/sector') as $region) {
  179.                             if ((int)$region->attributes()->mappingKey === $resortId) {
  180.                                 $additionalTitle '.specified';
  181.                             }
  182.                         }
  183.                     }
  184.                     if (!empty($item->xpath('sectors')) && $additionalTitle === null) {
  185.                         continue;
  186.                     }
  187.                 } catch (\Throwable $exception) {
  188.                     continue;
  189.                 }
  190.                 foreach ($item->xpath('text') as $text) {
  191.                     if ((int)$text->attributes()->lang === $languageMapping[$language]) {
  192.                         $data[] = [
  193.                             'title' => 'infosnow.' . ((string)$item->attributes()->priority === '1' 'warning' 'info') . $additionalTitle,
  194.                             'content' => (string)$text,
  195.                             'priority' => (string)$item->attributes()->priority,
  196.                         ];
  197.                     }
  198.                 }
  199.             }
  200.         } catch (Exception $exception) {
  201.         }
  202.         return $data;
  203.     }
  204.     /**
  205.      * @return array<mixed>
  206.      */
  207.     public function getFacilitiesCount(): array
  208.     {
  209.         $resort = new Resort\Listing();
  210.         $resort->addConditionParam('openLiftCount != 0 OR totalLiftCount != 0 OR openSlopeLength != 0 OR totalSlopeLength != 0');
  211.         $resort->setLimit(1);
  212.         $resort $resort->current();
  213.         return [
  214.             'openLifts' => $resort $resort->getOpenLiftCount() : 0,
  215.             'totalLifts' => $resort $resort->getTotalLiftCount() : 0,
  216.             'openSlopes' => $resort $resort->getOpenSlopeLength() : 0,
  217.             'totalSlopes' => $resort $resort->getTotalSlopeLength() : 0,
  218.         ];
  219.     }
  220.     /**
  221.      * @param Resort|null $resort
  222.      *
  223.      * @return array<mixed>
  224.      *
  225.      * @throws Exception
  226.      */
  227.     public function getFacilitiesViewData(Resort $resort nullstring $date nullstring $language 'de'): array
  228.     {
  229.         if (!$resort instanceof Resort) {
  230.             return [];
  231.         }
  232.         $conditions = [ 'area__id = :resortId' ];
  233.         $params = [ 'resortId' => $resort->getId() ];
  234.         if ($date) {
  235.             $date Carbon::createFromFormat('Y-m-d\\T00:00:00'$date)->startOfDay();
  236.             $conditions[] = 'o_id IN (select distinct id from bundle_recurringdates_occurrences where (dateFrom >= :dateFrom and dateTo <= :dateTo))';
  237.             $params['dateFrom'] = $date->format('Y-m-d H:i:s');
  238.             $params['dateTo'] = $date->endOfDay()->format('Y-m-d H:i:s');
  239.             $slopes = [];
  240.         } else {
  241.             $slopes $this->filterAndSortListing(new Slope\Listing(), $conditions$params);
  242.         }
  243.         $lifts $this->filterAndSortListing(new Lift\Listing(), $conditions$params);
  244.         $misc $this->filterAndSortListing(new Miscellaneous\Listing(), $conditions$params);
  245.         $salesPoints $this->filterAndSortListing(new Miscellaneous\Listing(), $conditions$paramstrue);
  246.         $lifts $this->customSortFunction($lifts->load());
  247.         $mappedLiftTypes = [];
  248.         foreach ($lifts as $lift) {
  249.             $mappedLiftType $this->getTypeImageMapping($lift);
  250.             if (!in_array($mappedLiftType$mappedLiftTypes)) {
  251.                 $mappedLiftTypes[] = $mappedLiftType;
  252.             }
  253.         }
  254.         return [
  255.             'modificationDate' => $this->getModificationDate(),
  256.             'snippet' => $resort->getSnippet(),
  257.             'liftTypes' => $mappedLiftTypes,
  258.             'slopeTypes' => $slopes $this->formService->getRelatedObjects($slopes'facilityType') : [],
  259.             'lifts' => $lifts,
  260.             'slopes' => $slopes $this->customSortFunction($slopes->load()) : [],
  261.             'misc' => $this->customSortFunction($misc->load()),
  262.             'salesPoints' => $this->customSortFunction($salesPoints->load()),
  263.             'weather' => DataObject\Weather::getByArea($resort1),
  264.             'warnings' => $this->getInfoSnowWarnings($language, (int)$resort->getInfosnowId()),
  265.         ];
  266.     }
  267.     public function getTypeImageMapping(Lift $lift): string
  268.     {
  269.         $type $lift->getFacilityType();
  270.         if (in_array($type, ['4''5''6''7'])) {
  271.             $type '9';
  272.         }
  273.         return $type;
  274.     }
  275.     public function isOpen(?DataObject $object null): bool
  276.     {
  277.         if ($object && method_exists($object'getStatus') &&
  278.             ($object->getStatus() == FacilityService::OPEN || $object->getStatus() == FacilityService::SLOPE_OPEN)) {
  279.             return true;
  280.         }
  281.         return false;
  282.     }
  283.     /**
  284.      * @param Concrete $listing
  285.      * @param array<mixed> $conditions
  286.      * @param array<mixed> $params
  287.      * @param bool $salesPoint
  288.      *
  289.      * @return Concrete
  290.      */
  291.     private function filterAndSortListing(Concrete $listing, array $conditions = [], array $params = [], bool $salesPoint false): Concrete
  292.     {
  293.         if ($listing instanceof Miscellaneous\Listing) {
  294.             $listing->addConditionParam('showOnWebsite = 1');
  295.             if($salesPoint) {
  296.                 $listing->addConditionParam('isSalesPoint = 1');
  297.             } else {
  298.                 $listing->addConditionParam('isSalesPoint IS NULL OR isSalesPoint != 1');
  299.             }
  300.         } else {
  301.             $listing->addConditionParam('hideOnWebsite IS NULL OR hideOnWebsite != 1');
  302.         }
  303.         if ($listing instanceof Lift\Listing) {
  304.             if (!array_key_exists('dateFrom'$params) && !array_key_exists('dateTo'$params) || array_key_exists('dateFrom'$params) && Carbon::parse($params['dateFrom'])->isToday()) {
  305.                 $conditions[] = 'o_id IN (select distinct id from bundle_recurringdates_occurrences where (dateFrom >= :dateFrom and dateTo <= :dateTo))';
  306.                 $params['dateFrom'] = Carbon::now()->startOfDay()->format('Y-m-d H:i:s');
  307.                 $params['dateTo'] = Carbon::now()->endOfDay()->format('Y-m-d H:i:s');
  308.             }
  309.         } else {
  310.             $listing->addConditionParam('status != :outOfOrder AND status != :slopeOutOfOrder', [
  311.                 'outOfOrder' => FacilityService::OUT_OF_ORDER,
  312.                 'slopeOutOfOrder' => FacilityService::SLOPE_OUT_OF_ORDER,
  313.             ]);
  314.             if ($listing instanceof Slope\Listing) {
  315.                 $listing->addConditionParam('status != :noInformation', [
  316.                     'noInformation' => FacilityService::NO_INFORMATION,
  317.                 ]);
  318.             }
  319.         }
  320.         if ($conditions != []) {
  321.             $listing->addConditionParam(implode(' AND '$conditions), $params);
  322.         }
  323.         $listing->setOrderKey(['status''sort']);
  324.         $listing->setOrder('ASC');
  325.         return $listing;
  326.     }
  327.     private function getModificationDate(): int
  328.     {
  329.         $lifts = new Lift\Listing();
  330.         $lifts->addConditionParam('hideOnWebsite IS NULL OR hideOnWebsite != 1');
  331.         $lifts->setOrderKey('o_modificationDate');
  332.         $lifts->setOrder('DESC');
  333.         $lifts->setLimit(1);
  334.         $lastModificatedLift $lifts->current();
  335.         return $lastModificatedLift->getModificationDate();
  336.     }
  337.     /**
  338.      * @param array<mixed> $objects
  339.      *
  340.      * @return array<mixed>
  341.      */
  342.     private function customSortFunction(array $objects): array
  343.     {
  344.         usort($objects, function ($a$b) {
  345.             $statusA $a->getStatus();
  346.             $statusB $b->getStatus();
  347.             if ($statusA == 0) {
  348.                 return 1;
  349.             }
  350.             if ($statusB == 0) {
  351.                 return -1;
  352.             }
  353.             $statusComparison = (int)$statusA - (int)$statusB;
  354.             if ($statusComparison !== 0) {
  355.                 return $statusComparison;
  356.             }
  357.             return $a->getSort() - $b->getSort();
  358.         });
  359.         return $objects;
  360.     }
  361.     private function getCachedData(string $uri, ?int $lifetime nullbool $disableCache false): mixed
  362.     {
  363.         $data null;
  364.         $cacheKey md5($uri);
  365.         if (!$disableCache) {
  366.             $data Cache::load($cacheKey);
  367.         }
  368.         if (!$data) {
  369.             try {
  370.                 $response $this->client->request('GET'$uri);
  371.                 if ($response->getStatusCode() === 200) {
  372.                     $data $response->getBody()->getContents();
  373.                     Cache::save(
  374.                         $data,
  375.                         $cacheKey,
  376.                         ['rss''warnings'],
  377.                         $lifetime
  378.                     );
  379.                 }
  380.             } catch (GuzzleException $e) {
  381.                 if (\Pimcore::inDebugMode()) {
  382.                     p_r($e);
  383.                 }
  384.             }
  385.         }
  386.         return $data;
  387.     }
  388. }