vendor/elements/demi-bundle/src/Elements/Demi/Accommodation/Search/Service/Vacancies/Local.php line 55

Open in your IDE?
  1. <?php
  2. /**
  3.  * Elements DeMI
  4.  *
  5.  * This source file is available under the elements DeMI license version 1
  6.  *
  7.  *  @copyright  Copyright (c) elements.at New Media Solutions GmbH (https://www.elements.at/)
  8.  *  @license    elements DeMI Lizenz Version 1 (https://www.elements.at/de/demi-lizenz)
  9.  */
  10. namespace Elements\Demi\Accommodation\Search\Service\Vacancies;
  11. use DateInterval;
  12. use DateTime;
  13. use Elements\Demi\Accommodation\Search\Parameter;
  14. use Elements\Demi\Accommodation\Search\Parameter\RoomRow;
  15. use Elements\Demi\Accommodation\Search\ResultSet;
  16. use Elements\Demi\Accommodation\Search\ResultSet\Accommodation;
  17. use Elements\Demi\Accommodation\Search\ResultSet\Product;
  18. use Elements\Demi\Accommodation\Search\Service\Vacancies\Local\SortFactory;
  19. use Elements\Demi\Deskline\Constant\SearchParameter\AccommodationInterface;
  20. use Elements\Demi\Model\AccommodationProduct;
  21. use Elements\Demi\Model\AccommodationServiceProvider;
  22. use Elements\Demi\Model\HousePackageMaster;
  23. use Elements\Demi\Model\Stars;
  24. use Elements\Demi\Vacancies\Dependency\VacancyDependencyContainer;
  25. use Exception;
  26. use JetBrains\PhpStorm\Pure;
  27. use Pimcore;
  28. /**
  29.  * Class Local
  30.  */
  31. class Local extends AbstractAdapter
  32. {
  33.     protected string $adapterCachePostFix 'Local';
  34.     protected int $count = -1;
  35.     protected array $sortFactories = [];
  36.     protected array $workResultPerFunction = [];
  37.     protected array $failedTasks = [];
  38.     protected array $workResult = [];
  39.     public function __construct(VacancyDependencyContainer $dc)
  40.     {
  41.         parent::__construct($dc);
  42.     }
  43.     #[Pure]
  44.  public function count(): ?int
  45.  {
  46.      return $this->resultSet->getTotalCount();
  47.  }
  48.     protected function detailSearch(): mixed
  49.     {
  50.         $searchParams $this->getSearchParameter();
  51.         $cacheId $this->getCacheId();
  52.         if (!($builtResult $this->getDc()->getFromCache($cacheId))) {
  53.             $resultBuilder $this->getResultBuilder();
  54.             $resultArrays = [];
  55.             foreach ($searchParams->getRoomrows() as $roomrow) {
  56.                 $selectFields = [];
  57.                 $selectFields[] = 'dacco.fid';
  58.                 $selectFields[] = 'dacco.isTop';
  59.                 $selectFields[] = 'dacco.bestPrice';
  60.                 $selectFields[] = 'dacco.oo_id';
  61.                 $selectFields[] = 'p.product_id';
  62.                 $selectFields[] = 'p.productType';
  63.                 $selectFields[] = 'p.serviceId';
  64.                 $selectFields[] = 'p.availabilityReference';
  65.                 $selectFields[] = 'p.kurtaxeObjId';
  66.                 $selectFields[] = 'max(p.gap_id) as gap_id';
  67.                 $selectFields[] = 'max(p.vacancies) vacancies';
  68.                 $selectFields[] = 'dacco.position__longitude as lng';
  69.                 $selectFields[] = 'dacco.position__latitude as lat ';
  70.                 if ($searchParams->getSearchType() == Parameter::SEARCH_TYPE_ONE_PRODUCT_PER_PACKAGE) {
  71.                     $selectFields[] = 'hpMasters.src_id as hpMaster_id';
  72.                 }
  73.                 // Map Stuff
  74.                 if ($searchParams->getExtendedResultset()) {
  75.                     $selectFields[] = 'stars.starsNumbers as starNr';
  76.                     $selectFields[] = 'stars.isSuperior as starSup';
  77.                     $selectFields[] = 'addressColl.addressLine1';
  78.                     $selectFields[] = 'addressColl.addressLine2';
  79.                     $selectFields[] = 'addressColl.zipCode';
  80.                     $selectFields[] = 'addressColl.town';
  81.                     $selectFields[] = 'addressColl.city';
  82.                     $selectFields[] = 'addressColl.country';
  83.                     $selectFields[] = 'dacco.' $this->getDc()->getRatingAverageColumn() . ' as ratingAverage';
  84.                     $selectFields[] = 'dacco.' $this->getDc()->getRatingCountColumn() . ' as ratingCount';
  85.                     $selectFields[] = 'dacco.name as accoName';
  86.                 }
  87.                 // Map Stuff END
  88.                 $query 'SELECT ' implode(', '$selectFields) . ' ';
  89.                 $query .= $this->getSqlFromPart();
  90.                 if ($searchParams->getSearchType() == Parameter::SEARCH_TYPE_ONE_PRODUCT_PER_PACKAGE) {
  91.                     // House Package Master
  92.                     $dummyHpMaster = new HousePackageMaster();
  93.                     $query .= ' INNER JOIN ' $this->getDc()->getUsedPimcoreDb() . '.object_relations_' $dummyHpMaster->getClassId() . ' hpMasters ON hpMasters.dest_id = p.product_id';
  94.                 }
  95.                 if ($searchParams->getExtendedResultset() || $searchParams->getStarsTableNeeded()) {
  96.                     $dummyStar = new Stars();
  97.                     $query .= ' LEFT JOIN ' $this->getDc()->getUsedPimcoreDb() . '.object_' $dummyStar->getClassId() . ' stars ON dacco.stars__id = stars.oo_id ';
  98.                 }
  99.                 // Map Stuff
  100.                 if ($searchParams->getExtendedResultset()) {
  101.                     $dummyAcco = new AccommodationServiceProvider();
  102.                     $query .= ' LEFT JOIN ' $this->getDc()->getUsedPimcoreDb() . '.object_collection_demiAddress_' $dummyAcco->getClassId() . " addressColl ON addressColl.o_id = dacco.oo_id AND addressColl.fieldname = 'addresses' AND addressColl.addressType = 'Object' ";
  103.                 }
  104.                 // Map Stuff END
  105.                 $query .= $this->getCondition($roomrow);
  106.                 // Map Stuff
  107.                 if ($searchParams->getExtendedResultset()) {
  108.                     $query .= ' AND dacco.name IS NOT NULL ';
  109.                 }
  110.                 // Map Stuff END
  111.                 // Closed Periods
  112.                 if ($searchParams->getDateFrom() && $searchParams->getDateTo()) {
  113.                     $dummyAcco = new AccommodationServiceProvider();
  114.                     $query .= ' AND dacco.oo_id NOT IN (SELECT o_id FROM ' $this->getDc()->getUsedPimcoreDb() . '.object_collection_demiClosedPeriods_' $dummyAcco->getClassId() . '
  115.                     WHERE (' $searchParams->getDateFrom()->getTimestamp() . ' BETWEEN ' $this->getDc()->getUsedPimcoreDb() . '.object_collection_demiClosedPeriods_' $dummyAcco->getClassId() . '.start AND ' $this->getDc()->getUsedPimcoreDb() . '.object_collection_demiClosedPeriods_' $dummyAcco->getClassId() . '.end)
  116.                     OR (' $searchParams->getDateTo()->getTimestamp() . ' BETWEEN ' $this->getDc()->getUsedPimcoreDb() . '.object_collection_demiClosedPeriods_' $dummyAcco->getClassId() . '.start AND ' $this->getDc()->getUsedPimcoreDb() . '.object_collection_demiClosedPeriods_' $dummyAcco->getClassId() . '.end)) ';
  117.                 }
  118.                 // Closed Periods end
  119.                 if ($searchParams->getSearchType() == Parameter::SEARCH_TYPE_ONE_PRODUCT_PER_PACKAGE) {
  120.                     //make sure only published HPM are used
  121.                     $query .= ' AND hpMasters.src_id in (select o_id from ' $this->getDc()->getUsedPimcoreDb() . '.object_' $dummyHpMaster->getClassId() . ' where o_published = 1 and active=1)';
  122.                 }
  123.                 $query .= ' group by p.product_id';
  124.                 $baseOrder $this->getBaseOrderBy();
  125.                 if (!empty($baseOrder)) {
  126.                     $query .= ' ORDER BY ' $baseOrder;
  127.                 } else {
  128.                     $query .= ' ORDER BY NULL';
  129.                 }
  130.                 //print_r($this->readifySql($query, $this->getBindParamsLegacy($roomrow)));die();
  131.                 if (isset($_GET['readifySql']) && $_GET['readifySql'] === '1d' && Pimcore::inDebugMode()) {
  132.                     print_r($this->readifySql($query$this->getBindParams($roomrow)));
  133.                     die();
  134.                 }
  135.                 $time = (round(microtime(true) * 1000));
  136.                 $stmt $this->getDc()->getDb()->executeQuery($query$this->getBindParams($roomrow));
  137.                 $timeTaken = (round(microtime(true) * 1000)) - $time;
  138.                 if (isset($_GET['gimmetime']) && $_GET['gimmetime'] && Pimcore::inDebugMode()) {
  139.                     p_r('query ' $timeTaken);
  140.                 }
  141.                 if (isset($_GET['readifySql']) && $_GET['readifySql'] === '1' && Pimcore::inDebugMode()) {
  142.                     print_r($this->readifySql($query$this->getBindParams($roomrow)));
  143.                     print_r($timeTaken);
  144.                 }
  145.                 $resultArrays[] = $stmt->fetchAll();
  146.             }
  147.             if (count($resultArrays) > 1) {
  148.                 if ($searchParams->getUseMultiLineMerge()) {
  149.                     $builtResult $this->mergeMultipleLines($resultArrays);
  150.                 } else {
  151.                     $builtResult $this->intersectResults($resultArrays);
  152.                 }
  153.                 $this->setResultSetMinpriceAndRange($builtResult);
  154.             } else {
  155.                 $finishedArray $resultArrays[0];
  156.                 $resultBuilder->setCheckBookable(true);
  157.                 $builtResult $resultBuilder->buildResult($finishedArray);
  158.             }
  159.             if (isset($_GET['readifyResult'])) {
  160.                 if ($_GET['readifyResult'] === '1' && Pimcore::inDebugMode()) {
  161.                     p_r($resultArrays);
  162.                     p_r($builtResult);
  163.                 }
  164.                 if ($_GET['readifyResult'] === '1d' && Pimcore::inDebugMode()) {
  165.                     p_r($resultArrays);
  166.                     p_r($builtResult);
  167.                     die();
  168.                 }
  169.             }
  170.             $this->getDc()->saveToCache($builtResult$cacheId);
  171.         }
  172.         return $builtResult;
  173.     }
  174.     public function searchVacancies(bool $force false): mixed
  175.     {
  176.         $searchParams $this->getSearchParameter();
  177.         $this->setSearchParameter($searchParams);
  178.         $cacheid $this->getDc()->getIdGenerator()?->generateCompleteCacheKey($searchParams);
  179.         if ($force || !$cacheid || !$builtResult $this->getDc()->getFromCache($cacheid)) {
  180.             $builtResult null;
  181.             if ($this->doBaseSearch()) {
  182.                 $builtResult $this->detailSearch();
  183.             }
  184.             $withResult false;
  185.             if ($builtResult) {
  186.                 $withResult true;
  187.             }
  188.             // "refilter" also for Acco List
  189.             $customOrder $searchParams->getRefilterCustomOrder();
  190.             if ($this->doRefilter($withResult) || !$builtResult || !empty($customOrder) || $searchParams->getSearchType() == Parameter::SEARCH_TYPE_ONE_PRODUCT_PER_PACKAGE) {
  191.                 $builtResult $this->reFilterDetails($builtResult);
  192.             }
  193.             $resultBuilder $this->getResultBuilder();
  194.             //do PHP filtering and sorting after everything has been built
  195.             if ($searchParams->getSkipBaseFilter()) {
  196.                 $builtResultAccommodations $builtResult->getAccommodations();
  197.             } else {
  198.                 if (method_exists($this'beforePhpSortingAndFiltering')) {
  199.                     $this->beforePhpSortingAndFiltering($builtResult);
  200.                 }
  201.                 $builtResultAccommodations $builtResult->getAccommodations();
  202.                 $this->iterateFilterResultSet($builtResultAccommodations);
  203.                 $this->setResultSetMinpriceAndRange($builtResult);
  204.                 $this->sortForPrice($builtResultAccommodations);
  205.                 if (!$searchParams->isNoDate()) {
  206.                     $this->getSatisfactionForAccommodations($builtResultAccommodations);
  207.                 }
  208.             }
  209.             if ($searchParams->getTopFirst() > || $searchParams->getAllTopsFirst()) {
  210.                 $topCount null;
  211.                 if (!$searchParams->getAllTopsFirst()) {
  212.                     $topCount $searchParams->getTopFirst();
  213.                 }
  214.                 $resultBuilder->sortTopsFirst($builtResultAccommodations$topCount);
  215.             }
  216.             $builtResult->setAccommodations($builtResultAccommodations);
  217.             $builtResult->setTotalCount(count($builtResultAccommodations));
  218.             $this->getDc()->saveToCache($builtResult$cacheid);
  219.         }
  220.         $this->resultSet $builtResult;
  221.         if ($searchParams->getDateFrom() && $searchParams->getDateFrom()->getTimestamp() < mktime(2359593152020)) {
  222.             $builtResult->setAccommodations([]);
  223.             $builtResult->setTotalCount(0);
  224.         }
  225.         return $builtResult;
  226.     }
  227.     public function getSatisfactionForAccommodations(array &$accommodations): void
  228.     {
  229.         foreach ($accommodations as $accoId => $acco) {
  230.             if (!$this->getSatisfaction($acco)) {
  231.                 unset($accommodations[$accoId]);
  232.             }
  233.         }
  234.     }
  235.     public function intersectResults(array $resultArrays): ResultSet
  236.     {
  237.         $resultSets = [];
  238.         foreach ($resultArrays as $roomrowIndex => $resultArray) {
  239.             $resultSets[] = $this->getResultBuilder()->buildResult($resultArray'EUR'$roomrowIndex);
  240.         }
  241.         $intersectedAccos array_keys($resultSets[0]->getAccommodations());
  242.         foreach ($resultSets as $index => $resultSet) {
  243.             if ($index == 0) {
  244.                 continue;
  245.             }
  246.             $intersectedAccos array_intersect($intersectedAccosarray_keys($resultSet->getAccommodations()));
  247.         }
  248.         $actualResultSet $resultSets[0];
  249.         $actualResultSet->removeAllBut($intersectedAccosfalsefalse);
  250.         foreach ($resultSets as $index => $resultSet) {
  251.             if ($index == 0) {
  252.                 continue;
  253.             }
  254.             $resultSet->removeAllBut($intersectedAccosfalsefalse);
  255.             $accos $resultSet->getAccommodations();
  256.             foreach ($accos as $acco) {
  257.                 $actualResultSet->addRoomRowToAcco($acco);
  258.             }
  259.         }
  260.         return $actualResultSet;
  261.     }
  262.     protected function refilterNeededFromFilters(): bool
  263.     {
  264.         $searchParams $this->getSearchParameter();
  265.         foreach ($this->refilterKeys as $rKey) {
  266.             $getter 'get' ucfirst($rKey);
  267.             $is 'is' ucfirst($rKey);
  268.             if (method_exists($searchParams$getter)) {
  269.                 $check $searchParams->$getter();
  270.             } elseif (method_exists($searchParams$is)) {
  271.                 $check $searchParams->$is();
  272.             } else {
  273.                 continue;
  274.             }
  275.             if (!empty($check)) {
  276.                 return true;
  277.             }
  278.         }
  279.         return false;
  280.     }
  281.     private function doRefilter(bool $withResultSet false): bool
  282.     {
  283.         $searchParams $this->getSearchParameter();
  284.         if ($this->refilterNeededFromFilters()) {
  285.             return true;
  286.         }
  287.         foreach ((array)$searchParams->getOrderKey() as $oKey) {
  288.             if (in_array($oKey$this->refilterOrderKeysfalse)) {
  289.                 return true;
  290.             }
  291.         }
  292.         if ($withResultSet) {
  293.             return false;
  294.         }
  295.         $orderKeys = (array)$searchParams->getOrderKey();
  296.         $baseOrderKeys array_keys($this->baseOrderKeys);
  297.         foreach ($orderKeys as $orderKey) {
  298.             if (!in_array($orderKey$baseOrderKeysfalse)) {
  299.                 return true;
  300.             }
  301.         }
  302.         return false;
  303.     }
  304.     protected function doBaseSearch(): bool
  305.     {
  306.         return $this->getSearchParameter()->validateRequiredVacancySearchParameter();
  307.     }
  308.     public function mergeMultipleLines(array $resultArrays): ResultSet
  309.     {
  310.         return $this->intersectResults($resultArrays);
  311.     }
  312.     public function getSatisfaction(Accommodation $acco): bool
  313.     {
  314.         return $this->getSatisfactionWithType($acco'Package') || $this->getSatisfactionWithType($acco'Accommodation');
  315.     }
  316.     public function getSatisfactionWithType(Accommodation $accostring $type): bool
  317.     {
  318.         $roomRows $acco->getRoomRows();
  319.         $rowCount count($roomRows);
  320.         $tmpRoomRows $roomRows;
  321.         $vacancies = [];
  322.         foreach ($roomRows as $roomRow) {
  323.             foreach ($roomRow->getProducts() as $product) {
  324.                 if ($product->getProductType() == $type) {
  325.                     $idToUse = (int)$product->getServiceId();
  326.                     if ($product->getAvailabilityReference() === 'Gap') {
  327.                         $idToUse $product->getGapId();
  328.                     } elseif ($product->getAvailabilityReference() === 'Product') {
  329.                         $idToUse $product->getProductId();
  330.                     }
  331.                     if (!isset($vacancies[$idToUse])) {
  332.                         $vacancies[$idToUse] = (int)$product->getUnits();
  333.                     }
  334.                 }
  335.             }
  336.         }
  337.         foreach ($roomRows as $index => $roomRow) {
  338.             if (!$roomRow->getRowObject()) {
  339.                 return true;
  340.             }
  341.             $neededVacancies $roomRow->getRowObject()->getUnits();
  342.             $products $roomRow->getProducts();
  343.             $tmpAllProducts = [];
  344.             for ($i $index 1$i $rowCount$i++) {
  345.                 $tmpAllProducts += $tmpRoomRows[$i]->getProducts();
  346.             }
  347.             unset($tmpRoomRows[$index]);
  348.             $productDiff array_diff_key($products$tmpAllProducts);
  349.             $productDiff array_filter($productDiff, static function ($prod) use ($type) {
  350.                 return $prod->getProductType() == $type;
  351.             });
  352.             $tmpAllProducts array_filter($tmpAllProducts, static function ($prod) use ($type) {
  353.                 return $prod->getProductType() == $type;
  354.             });
  355.             $products array_filter($products, static function ($prod) use ($type) {
  356.                 return $prod->getProductType() == $type;
  357.             });
  358.             /**
  359.              * @var  $key
  360.              * @var Product $pDiff
  361.              */
  362.             foreach ($productDiff as $key => $pDiff) {
  363.                 //$neededVacancies = $neededVacancies - $pDiff->getUnits();
  364.                 $idToUse 0;
  365.                 if ($pDiff->getAvailabilityReference() === 'Service') {
  366.                     $idToUse $pDiff->getServiceId();
  367.                 } elseif ($pDiff->getAvailabilityReference() === 'Gap') {
  368.                     $idToUse $pDiff->getGapId();
  369.                 } elseif ($pDiff->getAvailabilityReference() === 'Product') {
  370.                     $idToUse $pDiff->getProductId();
  371.                 }
  372.                 if(isset($vacancies[$idToUse])) {
  373.                     $unitsToUse $vacancies[$idToUse];
  374.                     if ($neededVacancies $unitsToUse) {
  375.                         $vacancies[$idToUse] -= $neededVacancies;
  376.                         $neededVacancies 0;
  377.                     } else {
  378.                         $vacancies[$idToUse] = 0;
  379.                         $neededVacancies -= $unitsToUse;
  380.                     }
  381.                 }
  382.                 if ($neededVacancies == 0) {
  383.                     break;
  384.                 }
  385.                 $products[$key] = $pDiff;
  386.             }
  387.             if ($neededVacancies == 0) {
  388.                 continue; //row already satisfied
  389.             }
  390.             // now check intersected Products
  391.             $reverseProductDiff array_intersect_key($tmpAllProducts$products);
  392.             foreach ($reverseProductDiff as $rProduct) {
  393.                 $useFromProduct null;
  394.                 foreach ($tmpRoomRows as $tmpRoomRow) {
  395.                     $tmpUseFromProducts $tmpRoomRow->getMaxPossibleVacanciesForProduct($rProduct$type);
  396.                     if (($useFromProduct === null || $tmpUseFromProducts $useFromProduct) && !($tmpUseFromProducts 0)) { // function returns -1 if products does not exists in row
  397.                         $useFromProduct $tmpUseFromProducts;
  398.                     }
  399.                 }
  400.                 if ($useFromProduct == 0) {
  401.                     continue; //product needed for other rows
  402.                 }
  403.                 if ($neededVacancies $useFromProduct) {
  404.                     $subtractFromProduct $neededVacancies;
  405.                     $neededVacancies 0;
  406.                 } else {
  407.                     $subtractFromProduct $useFromProduct;
  408.                     $neededVacancies -= $subtractFromProduct;
  409.                 }
  410.                 foreach ($roomRows as $tmpRoomRow) {
  411.                     $tmpRoomRow->subtractFromProduct($subtractFromProduct$rProduct);
  412.                 }
  413.                 if ($neededVacancies == 0) {
  414.                     break; //satisfied
  415.                 }
  416.             }
  417.             if ($neededVacancies != 0) {
  418.                 return false//I can't get no satisfaction
  419.             }
  420.         }
  421.         return true;
  422.     }
  423.     public function getCacheId(): ?string
  424.     {
  425.         if ($this->getDc()->getIdGenerator()) {
  426.             return $this->getDc()->getIdGenerator()->generateVacancyKey($this->getSearchParameter());
  427.         }
  428.         return null;
  429.     }
  430.     protected function getSqlFromPart(): string
  431.     {
  432.         $dummyAcco = new AccommodationServiceProvider();
  433.         $pimcoreDB $this->getDc()->getUsedPimcoreDb();
  434.         $demiDB $this->getDc()->getVacanciesDb();
  435.         return "FROM $pimcoreDB.object_" $dummyAcco->getClassId() . " dacco
  436.                 INNER JOIN $demiDB." $this->getDc()->getOccupancyTableName() . " occupancy ON occupancy.acco_id = dacco.o_id
  437.                 INNER JOIN $demiDB." $this->getDc()->getFromtoTableName() . " fromto ON occupancy.id = fromto.occu_id
  438.                 INNER JOIN $demiDB." $this->getDc()->getFromtoProductsTableName() . ' p ON fromto.id = p.fromto_id';
  439.     }
  440.     protected function getCondition(RoomRow $roomrow): string
  441.     {
  442.         $searchParams $this->getSearchParameter();
  443.         $accoidadd '';
  444.         $prodidadd '';
  445.         $accoids $searchParams->getAccoIds();
  446.         $excludeAccoids $searchParams->getExcludeAccoIds();
  447.         $accoidaddArray = [];
  448.         if (!empty($accoids)) {
  449.             $ids = [];
  450.             foreach ($accoids as $accoid) {
  451.                 $ids[] = (int)$accoid;
  452.             }
  453.             $accoidaddArray[] = 'dacco.oo_id IN (' implode(', '$ids) . ') ';
  454.         }
  455.         if (!empty($excludeAccoids)) {
  456.             $ids = [];
  457.             foreach ($excludeAccoids as $accoid) {
  458.                 $ids[] = (int)$accoid;
  459.             }
  460.             $accoidaddArray[] = 'dacco.oo_id NOT IN (' implode(', '$ids) . ') ';
  461.         }
  462.         if (!empty($accoidaddArray)) {
  463.             $accoidadd ' AND ( ' implode(' AND '$accoidaddArray) . ' ) ';
  464.         }
  465.         $preSelectedProductIds = [];
  466.         $productIds = (array)$searchParams->getProductIds();
  467.         foreach ($productIds as $prodId) {
  468.             $preSelectedProductIds[] = (int)$prodId;
  469.         }
  470.         if (!empty($preSelectedProductIds)) {
  471.             $prodidadd ' AND ';
  472.             $prodidadd .= 'p.product_id IN (' implode(', '$preSelectedProductIds) . ') ';
  473.         }
  474.         $arrivalDay 'arrival' $searchParams->getDateFrom()->format('D');
  475.         $departureDay 'departure' $searchParams->getDateTo()->format('D');
  476.         $string =
  477.             ' WHERE
  478.                 dacco.o_published = 1 AND
  479.                        occupancy.beds = ? AND
  480.                           fromto.period >= ?
  481.                           AND DATEDIFF(?, fromto.fromDate) >= ?
  482.                           AND DATEDIFF(fromto.toDate, ?) >= ?
  483.                   AND NOT EXISTS (
  484.                     SELECT 1
  485.                       FROM ' $this->getDc()->getVacanciesDb() . '.' $this->getDc()->getArrivalTemplateTableName() . ' arrival
  486.                      WHERE     arrival.product_id = p.product_id
  487.                            AND arrival.gap_id = p.gap_id
  488.                            AND (    (   ? BETWEEN arrival.dateFrom AND arrival.dateTo
  489.                                      OR ? BETWEEN arrival.dateFrom AND arrival.dateTo
  490.                                      OR arrival.dateFrom BETWEEN ? AND ?
  491.                                      OR arrival.dateTo BETWEEN ? AND ?)
  492.                                 AND ? BETWEEN arrival.daysUntilArrivalFrom
  493.                                            AND arrival.daysUntilArrivalTo
  494.                                 AND ' $this->getDc()->getDb()?->quote($this->today->format('Y-m-d')) . " >= arrival.validFrom
  495.                                            )
  496.                            AND (
  497.                                     (
  498.                                         ? != arrival.dateFrom
  499.                                         AND (   arrival.minStay > ?  OR arrival.maxStay < ?)
  500.                                         AND (
  501.                                             ? BETWEEN arrival.dateFrom AND arrival.dateTo
  502.                                             OR arrival.minStayFromArrivalDay = 0
  503.                                             )
  504.                                     )
  505.                                     OR (    ? BETWEEN arrival.dateFrom AND arrival.dateTo
  506.                                         AND (   arrival.$arrivalDay != 1
  507.                                              OR IFNULL((? % arrival.dayInterval), 0) != 0))
  508.                                     OR (    ? BETWEEN arrival.dateFrom AND arrival.dateTo
  509.                                         AND arrival.$departureDay != 1))
  510.                             )
  511.                   AND EXISTS (
  512.                     SELECT 1
  513.                       FROM " $this->getDc()->getVacanciesDb() . '.' $this->getDc()->getArrivalTemplateTableName() . ' arrival
  514.                      WHERE     arrival.product_id = p.product_id
  515.                            AND arrival.gap_id = p.gap_id
  516.                            AND (    (   ? BETWEEN arrival.dateFrom AND arrival.dateTo
  517.                                      OR ? BETWEEN arrival.dateFrom AND arrival.dateTo
  518.                                      OR arrival.dateFrom BETWEEN ? AND ?
  519.                                      OR arrival.dateTo BETWEEN ? AND ?)
  520.                                 AND ? BETWEEN arrival.daysUntilArrivalFrom
  521.                                            AND arrival.daysUntilArrivalTo
  522.                                 AND ' $this->getDc()->getDb()?->quote($this->today->format('Y-m-d')) . ' >= arrival.validFrom
  523.                                            )
  524.                   )
  525.                   AND (NOT EXISTS
  526.                     (SELECT 1
  527.                         FROM ' $this->getDc()->getVacanciesDb() . '.' $this->getDc()->getSalesRulesTemplateTableName() . ' salesrule
  528.                         WHERE     salesrule.product_id = p.product_id
  529.                             AND ' $this->getDc()->getDb()?->quote($searchParams->getDateFrom()->format('Y-m-d')) . ' >= salesrule.validFrom
  530.                             AND (   (' $this->getDc()->getDb()?->quote($searchParams->getDateFrom()->format('Y-m-d')) . ' >= salesrule.dateFrom
  531.                                      AND ' $this->getDc()->getDb()?->quote($searchParams->getDateFrom()->format('Y-m-d')) . ' < salesrule.dateTo)
  532.                               OR (' $this->getDc()->getDb()?->quote($searchParams->getDateTo()->format('Y-m-d')) . ' > salesrule.dateFrom
  533.                                      AND ' $this->getDc()->getDb()?->quote($searchParams->getDateTo()->format('Y-m-d')) . ' <= salesrule.dateTo)
  534.                               OR (salesrule.dateFrom >= ' $this->getDc()->getDb()?->quote($searchParams->getDateFrom()->format('Y-m-d')) . '
  535.                                      AND salesrule.dateFrom < ' $this->getDc()->getDb()?->quote($searchParams->getDateTo()->format('Y-m-d')) . ')
  536.                               OR (salesrule.dateTo >= ' $this->getDc()->getDb()?->quote($searchParams->getDateFrom()->format('Y-m-d')) . '
  537.                                      AND salesrule.dateTo < ' $this->getDc()->getDb()?->quote($searchParams->getDateTo()->format('Y-m-d')) . '))
  538.                               AND salesrule.offerable = 0)
  539.                        )
  540.                   AND (
  541.                   EXISTS
  542.                    (SELECT 1
  543.                       FROM ' $this->getDc()->getVacanciesDb() . '.' $this->getDc()->getSalesRulesTemplateTableName() . ' salesrule
  544.                      WHERE     salesrule.product_id = p.product_id
  545.                            AND ' $this->getDc()->getDb()?->quote($searchParams->getDateFrom()->format('Y-m-d')) . ' >= salesrule.validFrom
  546.                            AND ? BETWEEN salesrule.dateFrom
  547.                                                 AND salesrule.dateTo
  548.                            AND DATEDIFF(?, ?) >= salesrule.daysOfferStops
  549.                                       )
  550.                   )
  551.                   AND (
  552.                     (' $roomrow->getAdults() . ' BETWEEN p.adultsMin AND p.adultsMax)
  553.                     AND
  554.                     (' count($roomrow->getChildAges()) . ' BETWEEN p.childrenMin AND p.childrenMax)
  555.                     AND
  556.                     ((' . (count($roomrow->getChildAges()) + $roomrow->getAdults()) . ' BETWEEN p.bedsMin AND p.bedsMax) OR (p.bedsMin = 0 AND p.bedsMax = 0))
  557.                   )
  558.                   ';
  559.         $accoType $roomrow->getAccommodationType();
  560.         if (!empty($accoType)) {
  561.             if ($accoType == AccommodationInterface::ACCOMMODATION_TYPE_APARTMENT
  562.                 || $accoType == AccommodationInterface::ACCOMMODATION_TYPE_CAMPING
  563.                 || $accoType == AccommodationInterface::ACCOMMODATION_TYPE_HOTELROOM
  564.             ) {
  565.                 $string .= " AND p.accommodationType = '" $accoType "' ";
  566.             }
  567.         }
  568.         $pType $searchParams->getProductType();
  569.         if (!empty($pType) && $pType === 'Product') {
  570.             $string .= " AND p.productType = '" AccommodationInterface::PRODUCT_TYPE_PACKAGE "'";
  571.         } elseif (!empty($pType) && $pType == AccommodationInterface::PRODUCT_TYPE_ACCOMMODATION) {
  572.             $string .= " AND p.productType = '" AccommodationInterface::PRODUCT_TYPE_ACCOMMODATION "'";
  573.         }
  574.         if (empty($pType) || $pType === 'Package') {
  575.             $string .=
  576.                 "
  577.                   AND (
  578.                     (
  579.                         p.productType != 'Package' OR p.validDateType != 'Period'
  580.                     )
  581.                     OR
  582.                     (
  583.                         EXISTS (
  584.                             SELECT 1 from " $this->getDc()->getVacanciesDb() . '.' $this->getDc()->getPackagePeriodTableName() . " pperiod
  585.                                 WHERE ('" $searchParams->getDateFrom()->format('Y-m-d') . "' BETWEEN pperiod.dateFrom AND pperiod.dateTo)
  586.                                   AND
  587.                                       ('" $searchParams->getDateTo()->format('Y-m-d') . "' BETWEEN pperiod.dateFrom AND pperiod.dateTo)
  588.                                   AND
  589.                                       pperiod.product_id = p.product_id
  590.                         )
  591.                     )
  592.                   )";
  593.         }
  594.         if ($searchParams->getLastAvailabilitiyChangeDays()) {
  595.             //$string .= " AND p.changeDate >= ? ";
  596.             $string .= ' AND (p.changeDate >= ?
  597.                 OR ((dacco.noChangeDateCheck = 0 OR dacco.noChangeDateCheck IS NULL) AND UNIX_TIMESTAMP(p.changeDate) >= UNIX_TIMESTAMP(CURRENT_TIMESTAMP - (dacco.changeDateExceptionDays * 24 * 60 * 60)))
  598.                 OR dacco.noChangeDateCheck = 1
  599.                 ) ';
  600.         }
  601.         $product = new AccommodationProduct();
  602.         $productRelationsTable 'object_relations_' $product->getClassId();
  603.         if ($searchParams->getSalesChannelId()) {
  604.             $string .= ' AND ' $searchParams->getSalesChannelId() . ' IN
  605.             (SELECT dest_id FROM ' $this->getDc()->getUsedPimcoreDb() . ".$productRelationsTable salesprodrel  WHERE salesprodrel.src_id = p.product_id)";
  606.         }
  607.         $string .= $accoidadd;
  608.         $string .= $prodidadd;
  609.         return $string;
  610.     }
  611.     protected function getBindParams(RoomRow $firstRoomConfig): array
  612.     {
  613.         $searchParams $this->getSearchParameter();
  614.         $period $searchParams->getPeriod();
  615.         //todo include childs
  616.         $array = [
  617.             $firstRoomConfig->getBeds(),
  618.             $period,
  619.             $searchParams->getDateTo()?->format('Y-m-d'),
  620.             $period,
  621.             $searchParams->getDateFrom()?->format('Y-m-d'),
  622.             $period,
  623.             $searchParams->getDateFrom()?->format('Y-m-d'),
  624.             $searchParams->getDateTo()?->format('Y-m-d'),
  625.             $searchParams->getDateFrom()?->format('Y-m-d'),
  626.             $searchParams->getDateTo()?->format('Y-m-d'),
  627.             $searchParams->getDateFrom()?->format('Y-m-d'),
  628.             $searchParams->getDateTo()?->format('Y-m-d'),
  629.             (int)$searchParams->getDaysUntilArrival(),
  630.             $searchParams->getDateTo()?->format('Y-m-d'),
  631.             $period//minStay
  632.             $period//maxStay
  633.             $searchParams->getDateFrom()?->format('Y-m-d'),
  634.             $searchParams->getDateFrom()?->format('Y-m-d'),
  635.             $period//interval
  636.             $searchParams->getDateTo()?->format('Y-m-d'),
  637.             $searchParams->getDateFrom()?->format('Y-m-d'),
  638.             $searchParams->getDateTo()?->format('Y-m-d'),
  639.             $searchParams->getDateFrom()?->format('Y-m-d'),
  640.             $searchParams->getDateTo()?->format('Y-m-d'),
  641.             $searchParams->getDateFrom()?->format('Y-m-d'),
  642.             $searchParams->getDateTo()?->format('Y-m-d'),
  643.             (int)$searchParams->getDaysUntilArrival(),
  644.             $searchParams->getDateFrom()?->format('Y-m-d'),
  645.             $searchParams->getDateFrom()?->format('Y-m-d'),
  646.             $this->today->format('Y-m-d'),
  647.         ];
  648.         if ($searchParams->getLastAvailabilitiyChangeDays()) {
  649.             $todayWithTime = new DateTime();
  650.             $pastDayWithTime = clone $todayWithTime;
  651.             $pastDayWithTime->sub(new DateInterval('P' . ($searchParams->getLastAvailabilitiyChangeDays()) . 'D'));
  652.             $array array_merge($array, [
  653.                 $pastDayWithTime->format('Y-m-d H:i:s'),
  654.             ]);
  655.         }
  656.         return $array;
  657.     }
  658.     /**
  659.      * @param ResultSet $resultSet
  660.      *
  661.      * @throws Exception
  662.      */
  663.     protected function beforePhpSortingAndFiltering(ResultSet $resultSet): void
  664.     {
  665.         $time1 = (round(microtime(true) * 1000));
  666.         if (!$this->getSearchParameter()->isNoDate()) {
  667.             $this->handleSalesRules($resultSet);
  668.             if (isset($_GET['gimmetime']) && Pimcore::inDebugMode()) {
  669.                 p_r('salesrules ' . ((round(microtime(true) * 1000)) - $time1));
  670.             }
  671.         }
  672.         $this->handlePrices($resultSet);
  673.         if (isset($_GET['gimmetime']) && Pimcore::inDebugMode()) {
  674.             p_r('prices ' . ((round(microtime(true) * 1000)) - $time1));
  675.         }
  676.     }
  677.     protected function handlePrices(ResultSet &$resultSet): void
  678.     {
  679.         $searchParams $this->getSearchParameter();
  680.         if (!$resultSet->getPricesSet()) {
  681.             $resultBuilder $this->getResultBuilder();
  682.             if ($searchParams->getDateFrom() && $searchParams->getDateTo()) {
  683.                 $resultBuilder->preparePriceCalc($resultSet);
  684.                 $resultSet->setPricesSet(true);
  685.             } else {
  686.                 if ($searchParams->getCalculateStandardPrice()) {
  687.                     if ($searchParams->getSearchType() == Parameter::SEARCH_TYPE_EACH_PRODUCT_SEPARATED ||
  688.                         $searchParams->getSearchType() == Parameter::SEARCH_TYPE_ONE_PRODUCT_PER_PACKAGE) {
  689.                         $resultBuilder->setProductStdPricesForResultSet($resultSet);
  690.                         $resultBuilder->setStdPricesForResultSet($resultSettrue);
  691.                     } else {
  692.                         $resultBuilder->setStdPricesForResultSet($resultSet);
  693.                     }
  694.                     $resultSet->setPricesSet(true);
  695.                 } else {
  696.                     $resultSet->setPricesSet(false);
  697.                 }
  698.             }
  699.             $resultSet->setPricesSet(true);
  700.             if (!$this->refilterNeededFromFilters()) {
  701.                 $this->getDc()->saveToCache($resultSet$this->getCacheId());
  702.             }
  703.         }
  704.     }
  705.     protected function handleSalesRules(ResultSet $resultSet): void
  706.     {
  707.         $resultbuilder $this->getResultBuilder();
  708.         $resultbuilder->getBookableForResultSet($resultSet);
  709.     }
  710.     #[Pure]
  711.  public function getSortFactoryKeys(): array
  712.  {
  713.      $keys = [];
  714.      foreach ($this->getSortFactories() as $factory) {
  715.          $keys[] = $factory->getOrderKey();
  716.      }
  717.      return $keys;
  718.  }
  719.     #[Pure]
  720.     public function getSortFactoryByKey(string $key): ?Local\SortFactory
  721.     {
  722.         $obj null;
  723.         foreach ($this->getSortFactories() as $factory) {
  724.             if ($factory->getOrderKey() == $key) {
  725.                 $obj $factory;
  726.             }
  727.         }
  728.         return $obj;
  729.     }
  730.     public function sortForPrice(&$accommodations, ?string $orderKey null): void
  731.     {
  732.         $searchParams $this->getSearchParameter();
  733.         $orderKeyes = (array) $searchParams->getOrderKey();
  734.         $sortFactoryKeys $this->getSortFactoryKeys();
  735.         foreach ($orderKeyes as $orderKey) {
  736.             if (in_array($orderKey$sortFactoryKeys)) {
  737.                 $obj $this->getSortFactoryByKey($orderKey);
  738.                 if (!$obj instanceof SortFactory) {
  739.                     continue;
  740.                 }
  741.                 $obj->sortAccos($accommodations);
  742.             } elseif ($orderKey === 'priceAsc') {
  743.                 $method 'cmpPrice';
  744.                 if (!$searchParams->getDateFrom()) { //nodate
  745.                     $method 'cmpPriceBase';
  746.                 }
  747.                 uasort($accommodations, [$this$method]);
  748.             } elseif ($orderKey === 'priceDesc') {
  749.                 $method 'cmpPriceDesc';
  750.                 if (!$searchParams->getDateFrom()) { //nodate
  751.                     $method 'cmpPriceDescBase';
  752.                 }
  753.                 uasort($accommodations, [$this$method]);
  754.             } elseif ($orderKey === 'bookable') {
  755.                 //only for requests with date; noDate requests are handled already via SQL order
  756.                 if ($searchParams->getDateFrom()) {
  757.                     uasort($accommodations, [$this'cmpBookable']);
  758.                 }
  759.             }
  760.         }
  761.         if (!$searchParams->isSkipCleaningSortAfterFactory() && $searchParams->getMinPrice() >= && !in_array('nearbySearchAsc'$orderKeyes) && !in_array('nearbySearchDesc'$orderKeyes)) {
  762.             $method 'getMinPrice';
  763.             if (!$searchParams->getDateFrom()) {
  764.                 $method 'getMinPriceBase';
  765.             }
  766.             $backArray = [];
  767.             $cleanArray = [];
  768.             foreach ($accommodations as $accoId => $acco) {
  769.                 if ($acco->$method() <= $searchParams->getMinPrice()) {
  770.                     $backArray[$accoId] = $acco;
  771.                 } else {
  772.                     $cleanArray[$accoId] = $acco;
  773.                 }
  774.             }
  775.             $accommodations $cleanArray $backArray;
  776.         }
  777.     }
  778.     public function getAdapterCachePostFix(): string
  779.     {
  780.         return $this->adapterCachePostFix;
  781.     }
  782.     /**
  783.      * @param ResultSet $resultSet
  784.      *
  785.      * @return array
  786.      *
  787.      * @throws Exception
  788.      */
  789.     public function splitResultSetIntoChunks($resultSet): array
  790.     {
  791.         $chunkSize $this->getDc()->getGearmanChunkSize();
  792.         $offset 0;
  793.         $resultSets = [];
  794.         while ($accos $resultSet->getAccommodations($offset$chunkSizetrue)) {
  795.             $offset += $chunkSize;
  796.             $tmpResultSet = new ResultSet($this->getSearchParameter(), $accos);
  797.             $resultSets[] = $tmpResultSet;
  798.         }
  799.         return $resultSets;
  800.     }
  801.     /**
  802.      * @param ResultSet $resultSet
  803.      *
  804.      * @return ResultSet
  805.      *
  806.      * @throws Exception
  807.      *
  808.      * @deprecated
  809.      *
  810.      */
  811.     public function launchGearmanPriceCalculation($resultSet): ResultSet
  812.     {
  813.         $resultSets $this->splitResultSetIntoChunks($resultSet);
  814.         $gmclient = new GearmanClient();
  815.         $gmclient->addServer();
  816.         $this->workResultPerFunction = [
  817.             'localSearch' => 0,
  818.         ];
  819.         $gmclient->setCompleteCallback(function (GearmanTask $task) {
  820.             //$functionIndex = $this->workResultPerFunction[$task->functionName()]++;
  821.             $data $task->data();
  822.             $info unserialize($data);
  823.             if ($info instanceof Exception) {
  824.                 $this->failedTasks[$task->functionName() . '_' $this->workResultPerFunction[$task->functionName()]] = $info->getMessage();
  825.             } else {
  826.                 $this->workResult[$task->functionName() . '_' $this->workResultPerFunction[$task->functionName()]] = $info;
  827.             }
  828.         });
  829.         $startWorkerCount 0;
  830.         //tasks have to be added AFTER the callbacks for some reason, probably getting their callback only on add/create from the client
  831.         foreach ($resultSets as $workload) {
  832.             $gmclient->addTask('priceCalculate'serialize($workload));
  833.             $startWorkerCount++;
  834.         }
  835.         //$gmclient->setTimeout(20000);
  836.         $startTime = (round(microtime(true) * 1000));
  837.         //start a backupworker for each task to ensure enough workers are available
  838.         for ($i 0$i $startWorkerCount$i++) {
  839.             exec('nohup php ' PIMCORE_PROJECT_ROOT DIRECTORY_SEPARATOR 'Demi/cli/gearman/priceWorker.php -t2000 > /dev/null 2>> dev/null &');
  840.         }
  841.         if (isset($_GET['gimmetime']) && Pimcore::inDebugMode()) {
  842.             p_r('Starting ' $startWorkerCount ' Workers. Time: ' . ((round(microtime(true) * 1000)) - $startTime));
  843.             p_r('nohup php ' PIMCORE_PROJECT_ROOT DIRECTORY_SEPARATOR 'Demi/cli/gearman/priceWorker.php -t10000 >/dev/null 2>/dev/null &');
  844.         }
  845.         $taskTime = (round(microtime(true) * 1000));
  846.         $gmclient->runTasks();
  847.         if (Pimcore::inDebugMode() && isset($_GET['gimmetime'])) {
  848.             p_r('Running tasks took time: ' . ((round(microtime(true) * 1000)) - $taskTime));
  849.         }
  850.         //build complete result
  851.         $completeResultSet = new ResultSet($this->getSearchParameter());
  852.         $allAccos = [];
  853.         foreach ($this->workResult as $function => $info) {
  854.             if (Pimcore::inDebugMode() && isset($_GET['gimmetime'])) {
  855.                 p_r('Running ' $function ' took time: ' $info['time']);
  856.                 p_r('RequestTime: ' $info['requestTime']);
  857.             }
  858.             /** @var $resultSet ResultSet */
  859.             $resultSet $info['resultSet'];
  860.             if (Pimcore::inDebugMode() && isset($_GET['gimmetime'])) {
  861.                 p_r('count: ' count($resultSet->getAccommodations()));
  862.                 p_r('total: ' $resultSet->getTotalCount());
  863.             }
  864.             if ($resultSet) {
  865.                 foreach ($resultSet->getAccommodations() as $accoId => $accoSet) {
  866.                     $allAccos[$accoId] = $accoSet;
  867.                 }
  868.             }
  869.         }
  870.         $completeResultSet->setAccommodations($allAccos);
  871.         $completeResultSet->setTotalCount(count($allAccos));
  872.         $completeResultSet->setPricesSet(true);
  873.         return $completeResultSet;
  874.     }
  875.     /**
  876.      * @return SortFactory[]
  877.      */
  878.     public function getSortFactories(): array
  879.     {
  880.         return $this->sortFactories;
  881.     }
  882.     /**
  883.      * @param SortFactory[] $sortFactories
  884.      */
  885.     public function setSortFactories($sortFactories)
  886.     {
  887.         $this->sortFactories $sortFactories;
  888.     }
  889. }