WIP Refactor filter/search logic

This commit is contained in:
Björn Fromme
2021-08-16 10:58:24 +02:00
parent f2b6f89633
commit d07c07786f
21 changed files with 285 additions and 1168 deletions
@@ -109,12 +109,9 @@ class AjaxDateController extends ActionController
public function datesAction(Product $product, Hotel $hotel = null, $paCode = null, $dateFrom = null, $dateTo = null)
{
$forcedConceptUids = GeneralUtility::trimExplode(',', $this->settings['forcedConceptUids'], true);
$filterSettings = $this->filterService->getDefaultFilterSettings(
$forcedConceptUids,
false,
$dateFrom,
$dateTo
);
$filterSettings = $this->filterService->getNormalizedFilterSettings([], $forcedConceptUids);
$filterSettings['dateFrom'] = $dateFrom;
$filterSettings['dateTo'] = $dateTo;
$altProductLink = null;
$altLabel = null;
@@ -28,7 +28,6 @@ namespace EP\EpProducts\Controller;
***************************************************************/
use EP\EpProducts\Service\FilterService;
use EP\EpProducts\Service\SearchResultUrlService;
use EP\EpProducts\Service\SearchResultService;
use EP\EpProducts\Traits\RequestArgumentTypeConversionTrait;
use EP\EpProducts\Utility\DateUtility;
@@ -50,36 +49,29 @@ class AjaxSearchController extends ActionController
*/
protected $searchResultService;
/**
* @var SearchResultUrlService
*/
protected $searchResultUrlService;
/**
* @param FilterService $filterService
* @param SearchResultService $searchResultService
* @param SearchResultUrlService $searchResultUrlService
*/
public function __construct
(
FilterService $filterService,
SearchResultService $searchResultService,
SearchResultUrlService $searchResultUrlService
) {
public function __construct(FilterService $filterService, SearchResultService $searchResultService)
{
parent::__construct();
$this->filterService = $filterService;
$this->searchResultService = $searchResultService;
$this->searchResultUrlService = $searchResultUrlService;
}
public function initializeSearchresultAction()
{
$forcedConceptUids = GeneralUtility::trimExplode(',', $this->settings['forcedConceptUids'], true);
$this->processFilterSettingsArgument($forcedConceptUids);
}
/**
* @param array $filterSettings
*/
public function searchresultAction(array $filterSettings = [])
public function searchresultAction(array $filterSettings)
{
$forcedConceptUids = GeneralUtility::trimExplode(',', $this->settings['forcedConceptUids'], true);
$dateSelected = false;
$organic = true;
$forcedConceptUids = GeneralUtility::trimExplode(',', $this->settings['forcedConceptUids'], true);
@@ -94,14 +86,12 @@ class AjaxSearchController extends ActionController
->searchResultService
->getResult($filterSettings, $excludedConceptUids);
if ($searchResult->getTotal() === 0) {
$filterSettings = $this->filterService->getDefaultFilterSettings($forcedConceptUids);
if (0 === $searchResult->getTotal()) {
$filterSettings = $this->filterService->getNormalizedFilterSettings([], $forcedConceptUids);
$searchResult = $this->searchResultService->getResult($filterSettings, $excludedConceptUids);
$organic = false;
}
$this->searchResultUrlService->process($searchResult, $this->settings['defaultDetailPageUid']);
$filterOptions = $this->filterService->getFilterOptions(
$filterSettings,
$excludedConceptUids,
@@ -117,7 +107,7 @@ class AjaxSearchController extends ActionController
'searchresult',
['filterSettings' => $filterSettings],
'Search',
null,
'epproducts',
'searchresult'
)
;
@@ -27,8 +27,8 @@ namespace EP\EpProducts\Controller;
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use EP\EpProducts\Domain\Model\SearchParams;
use EP\EpProducts\Service\FilterService;
use EP\EpProducts\Service\SearchResultService;
use EP\EpProducts\Traits\RequestArgumentTypeConversionTrait;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
@@ -44,12 +44,19 @@ class AjaxSearchbarController extends ActionController
protected $filterService;
/**
* @param FilterService $filterService
* @var SearchResultService
*/
public function __construct(FilterService $filterService)
protected $searchResultService;
/**
* @param FilterService $filterService
* @param SearchResultService $searchResultService
*/
public function __construct(FilterService $filterService, SearchResultService $searchResultService)
{
parent::__construct();
$this->filterService = $filterService;
$this->searchResultService = $searchResultService;
}
public function initializeAction()
@@ -58,18 +65,18 @@ class AjaxSearchbarController extends ActionController
}
/**
* @param SearchParams $searchParams
* @param array $searchParams
* @return string
*/
public function updateAction(SearchParams $searchParams = null)
public function updateAction(array $searchParams = null)
{
$forcedConceptUids = GeneralUtility::trimExplode(',', $this->settings['forcedConceptUids'], true);
if ($searchParams === null) {
$searchParams = new SearchParams();
$filterSettings = $this->filterService->getDefaultFilterSettings($forcedConceptUids);
if (null === $searchParams) {
$searchParams = $this->searchResultService->getNormalizedSearchParams();
$filterSettings = $this->filterService->getNormalizedFilterSettings([], $forcedConceptUids);
} else {
$filterSettings = $searchParams->toFilterSettings();
$filterSettings = $this->filterService->getFilterSettingsFromSearchParams($searchParams);
}
$excludedConceptUids = GeneralUtility::trimExplode(',', $this->settings['excludedConceptUids']);
$excludedRegionUids = GeneralUtility::trimExplode(',', $this->settings['excludedRegionUids']);
@@ -75,12 +75,6 @@ class AjaxTableController extends ActionController
$this->resellerDataService = $resellerDataService;
}
public function initializeAction()
{
$forcedConceptUids = GeneralUtility::trimExplode(',', $this->settings['forcedConceptUids'], true);
$this->processFilterSettingsArgument($forcedConceptUids);
}
/**
* @param Product $product
* @param Hotel $hotel
@@ -98,11 +92,12 @@ class AjaxTableController extends ActionController
$paCode = null
) {
$forcedConceptUids = GeneralUtility::trimExplode(',', $this->settings['forcedConceptUids'], true);
$filterSettings = $this->filterService->getDefaultFilterSettings($forcedConceptUids, false);
$filterSettings = $this->filterService->getNormalizedFilterSettings([], $forcedConceptUids);
if ($reseller = $this->resellerDataService->getResellerForCurrentDomain()) {
$paCode = $reseller['paCode'];
}
$priceTable = $this->dateService->getPriceTable([
'product' => $product,
'hotel' => $hotel,
@@ -138,7 +133,7 @@ class AjaxTableController extends ActionController
$pricetable = $this->dateService->getPriceTable([
'product' => $product,
'hotel' => $hotel,
'filterSettings' => $this->filterService->getDefaultFilterSettings(),
'filterSettings' => $this->filterService->getNormalizedFilterSettings(),
'template' => $this->settings['bpnBookingUrlTemplateCode'],
'paCode' => $paCode,
]);
@@ -30,7 +30,6 @@ namespace EP\EpProducts\Controller;
use EP\EpProducts\Domain\Repository\ProductRepository;
use EP\EpProducts\Service\FilterService;
use EP\EpProducts\Service\SearchResultService;
use EP\EpProducts\Service\SearchResultUrlService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
@@ -47,11 +46,6 @@ class AjaxWatchlistController extends ActionController
*/
protected $searchResultService;
/**
* @var SearchResultUrlService
*/
protected $searchResultUrlService;
/**
* @var FilterService
*/
@@ -60,14 +54,12 @@ class AjaxWatchlistController extends ActionController
/**
* @param ProductRepository $productRepository
* @param SearchResultService $searchResultService
* @param SearchResultUrlService $searchResultUrlService
* @param FilterService $filterService
*/
public function __construct
(
ProductRepository $productRepository,
SearchResultService $searchResultService,
SearchResultUrlService $searchResultUrlService,
FilterService $filterService
)
{
@@ -75,7 +67,6 @@ class AjaxWatchlistController extends ActionController
$this->productRepository = $productRepository;
$this->searchResultService = $searchResultService;
$this->searchResultUrlService = $searchResultUrlService;
$this->filterService = $filterService;
}
@@ -107,11 +98,6 @@ class AjaxWatchlistController extends ActionController
$watchlistData = $this->productRepository->getWatchlist($productUids, $hotelUids);
$watchlist = $this->searchResultService->preprocess($watchlistData);
$options = [
'defaultDetailPageUid' => $this->settings['defaultDetailPageUid'],
];
$this->searchResultUrlService->process($watchlist, $options);
$this->view->assignMultiple([
'watchlist' => $watchlist->getData(),
'total' => $watchlist->getTotal()
@@ -117,7 +117,7 @@ class ProductController extends ActionController
}
// Redirect to search page in case no product can be determined
if ($product === null) {
$filterSettings = $this->filterService->getDefaultFilterSettings();
$filterSettings = $this->filterService->getNormalizedFilterSettings();
$this->redirect(
'searchresult',
'Search',
@@ -202,7 +202,7 @@ class ProductController extends ActionController
$pricetable = $this->dateService->getPriceTable([
'product' => $product,
'hotel' => $hotel,
'filterSettings' => $this->filterService->getDefaultFilterSettings(),
'filterSettings' => $this->filterService->getNormalizedFilterSettings(),
]);
$this->view->assign('pricetable', $pricetable);
}
@@ -27,16 +27,13 @@ namespace EP\EpProducts\Controller;
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use EP\EpProducts\Domain\Model\SearchParams;
use EP\EpProducts\Service\FilterService;
use EP\EpProducts\Service\FilterSettingsEncoder;
use EP\EpProducts\Service\SearchResultService;
use EP\EpProducts\Service\SearchResultUrlService;
use EP\EpProducts\Traits\RequestArgumentTypeConversionTrait;
use EP\EpProducts\Utility\DateUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
class SearchController extends ActionController
{
@@ -53,53 +50,27 @@ class SearchController extends ActionController
*/
private $searchResultService;
/**
* @var SearchResultUrlService
*/
private $searchResultUrlService;
/**
* @var array
*/
protected $defaultFilterSettings;
/**
* @var \EP\EpProducts\Domain\Model\FilterOptions
*/
protected $defaultFilterOptions;
/**
* @param FilterService $filterService
*/
public function __construct
(
FilterService $filterService,
SearchResultService $searchResultService,
SearchResultUrlService $searchResultUrlService
) {
public function __construct(FilterService $filterService, SearchResultService $searchResultService)
{
parent::__construct();
$this->filterService = $filterService;
$this->searchResultService = $searchResultService;
$this->searchResultUrlService = $searchResultUrlService;
$forcedConceptUids = GeneralUtility::trimExplode(',', $this->settings['forcedConceptUids'], true);
$excludedConceptUids = GeneralUtility::trimExplode(',', $this->settings['excludedConceptUids'], true);
$excludedRegionUids = GeneralUtility::trimExplode(',', $this->settings['excludedRegionUids'], true);
$this->defaultFilterSettings = $this->filterService->getDefaultFilterSettings($forcedConceptUids);
$this->defaultFilterOptions = $this->filterService->getFilterOptions(
$this->defaultFilterSettings,
$excludedConceptUids,
$excludedRegionUids,
$forcedConceptUids
);
}
public function searchbarAction()
{
$fixed = (bool)$this->settings['fixed'];
$searchParams = new SearchParams($GLOBALS['TSFE']->id);
$searchParams = $this->searchResultService->getNormalizedSearchParams();
$filterSettings = $this->filterService->getNormalizedFilterSettings();
$filterOptions = $this->filterService->getFilterOptions($filterSettings);
$this->view->assignMultiple([
'filterSettings' => $this->defaultFilterSettings,
'filterOptions' => $this->defaultFilterOptions,
'filterSettings' => $filterSettings,
'filterOptions' => $filterOptions,
'searchParams' => $searchParams,
'fixed' => $fixed,
]);
@@ -107,10 +78,13 @@ class SearchController extends ActionController
public function searchboxAction()
{
$searchParams = new SearchParams($GLOBALS['TSFE']->id);
$searchParams = $this->searchResultService->getNormalizedSearchParams();
$filterSettings = $this->filterService->getNormalizedFilterSettings();
$filterOptions = $this->filterService->getFilterOptions($filterSettings);
$this->view->assignMultiple([
'filterSettings' => $this->defaultFilterSettings,
'filterOptions' => $this->defaultFilterOptions,
'filterSettings' => $filterSettings,
'filterOptions' => $filterOptions,
'searchParams' => $searchParams,
]);
}
@@ -121,11 +95,11 @@ class SearchController extends ActionController
}
/**
* @param SearchParams $searchParams
* @param array $searchParams
*/
public function processSearchAction(SearchParams $searchParams)
public function processSearchAction(array $searchParams)
{
$filterSettings = $searchParams->toFilterSettings();
$filterSettings = $this->filterService->getFilterSettingsFromSearchParams($searchParams);
$redirectUri = $this->uriBuilder
->reset()
@@ -144,13 +118,13 @@ class SearchController extends ActionController
public function initializeSearchresultAction()
{
$forcedConceptUids = GeneralUtility::trimExplode(',', $this->settings['forcedConceptUids'], true);
//$this->processFilterSettingsArgument($forcedConceptUids);
$this->processFilterSettingsArgument($forcedConceptUids);
}
/**
* @param array $filterSettings
*/
public function searchresultAction(array $filterSettings = [])
public function searchresultAction(array $filterSettings)
{
$dateSelected = false;
$organic = true;
@@ -165,13 +139,11 @@ class SearchController extends ActionController
$searchResult = $this->searchResultService->getResult($filterSettings, $excludedConceptUids);
if ($searchResult->getTotal() === 0) {
$filterSettings = $this->defaultFilterSettings;
$filterSettings = $this->filterService->getNormalizedFilterSettings([], $forcedConceptUids);
$searchResult = $this->searchResultService->getResult($filterSettings, $excludedConceptUids);
$organic = false;
}
$this->searchResultUrlService->process($searchResult, $this->settings['defaultDetailPageUid']);
$filterOptions = $this->filterService->getFilterOptions(
$filterSettings,
$excludedConceptUids,
@@ -187,7 +159,7 @@ class SearchController extends ActionController
'searchresult',
['filterSettings' => $filterSettings],
'Search',
null,
'epproducts',
'searchresult'
)
;
@@ -208,11 +180,11 @@ class SearchController extends ActionController
/**
* @param string $encodedFilterSettings
* @throws StopActionException
*/
public function staticresultAction($encodedFilterSettings)
{
$filterSettings = FilterSettingsEncoder::decode($encodedFilterSettings);
$filterSettingsEncoder = new FilterSettingsEncoder();
$filterSettings = $filterSettingsEncoder->decode($encodedFilterSettings);
$this->forward(
'searchresult',
@@ -1,503 +0,0 @@
<?php
namespace EP\EpProducts\Domain\Model;
/***************************************************************
*
* Copyright notice
*
* (c) 2016 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use EP\EpProducts\Utility\TypeConversionUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Request;
class FilterSettings implements \JsonSerializable
{
public const DURATION_SHORT = 4;
public const DURATION_LONG = 5;
/**
* @var array
*/
protected $priceRanges = [];
/**
* @var array
*/
protected $countryUids = [];
/**
* @var array
*/
protected $regionUids = [];
/**
* @var array
*/
protected $cityUids = [];
/**
* @var array
*/
protected $conceptUids = [];
/**
* @var int
*/
protected $hotelUid = 0;
/**
* @var int
*/
protected $productUid = 0;
/**
* @var \DateTime
*/
protected $dateFrom;
/**
* @var \DateTime
*/
protected $dateTo;
/**
* @var int
*/
protected $nights = 0;
/**
* @var int
*/
protected $pax = 0;
/**
* @var array
*/
protected $boardTypes = [];
/**
* @var array
*/
protected $hotelTypes = [];
/**
* @var array
*/
protected $roomTypes = [];
/**
* @var bool
*/
protected $bus;
public function __construct(\DateTime $dateFrom = null, \DateTime $dateTo = null)
{
if ($dateFrom !== null) {
$this->setDateFrom($dateFrom);
}
if ($dateTo !== null) {
$this->setDateTo($dateTo);
}
}
public static function fromSearchParams(SearchParams $searchParams): self
{
$filterSettings = new self;
if ($searchParams->getDestinationType() && $searchParams->getDestinationUid()) {
$destinationUid = $searchParams->getDestinationUid();
switch ($searchParams->getDestinationType()) {
case SearchParams::DESTINATION_TYPE_COUNTRY:
$filterSettings->setCountryUids([$destinationUid]);
break;
case SearchParams::DESTINATION_TYPE_REGION:
$filterSettings->setRegionUids([$destinationUid]);
break;
case SearchParams::DESTINATION_TYPE_CITY:
$filterSettings->setCityUids([$destinationUid]);
break;
case SearchParams::DESTINATION_TYPE_CONCEPT:
$filterSettings->setConceptUids([$destinationUid]);
break;
}
}
if (null !== $searchParams->getDateFrom()) {
$filterSettings->setDateFrom($searchParams->getDateFrom());
}
if (null !== $searchParams->getDateTo()) {
$filterSettings->setDateTo($searchParams->getDateTo());
}
if (null !== $searchParams->getPriceRange()) {
$filterSettings->setPriceRanges([$searchParams->getPriceRange()]);
}
if (null !== $searchParams->getPax()) {
$filterSettings->setPax($searchParams->getPax());
}
if (null !== $searchParams->getNights()) {
$filterSettings->setNights($searchParams->getNights());
}
return $filterSettings;
}
public static function fromStaticSearchParams(array $searchParams): self
{
$filterSettings = new self;
if (!empty($searchParams['country'])) {
$filterSettings->setCountryUids([$searchParams['country']]);
}
if (!empty($searchParams['region'])) {
$filterSettings->setRegionUids([$searchParams['region']]);
}
if (!empty($searchParams['concept'])) {
$conceptUids = GeneralUtility::trimExplode(',', $searchParams['concept']);
$filterSettings->setConceptUids($conceptUids);
}
if (!empty($searchParams['hotel'])) {
$filterSettings->setHotelUid($searchParams['hotel']);
}
if (!empty($searchParams['product'])) {
$filterSettings->setProductUid($searchParams['product']);
}
if (!empty($searchParams['hotel_types'])) {
$hotelTypes = explode(',', $searchParams['hotel_types']);
$filterSettings->setHotelTypes($hotelTypes);
}
if (!empty($searchParams['bus'])) {
$filterSettings->setBus((bool) $searchParams['bus']);
}
if (!empty($searchParams['date_from']) && $searchParams['date_from'] !== '0000-00-00') {
$dateFrom = new \DateTime($searchParams['date_from']);
$filterSettings->setDateFrom($dateFrom);
}
if (!empty($searchParams['date_to']) && $searchParams['date_to'] !== '0000-00-00') {
$dateTo = new \DateTime($searchParams['date_to']);
$filterSettings->setDateTo($dateTo);
}
if (!empty($searchParams['pax']) && (int) $searchParams['pax'] > 0) {
$filterSettings->setPax($searchParams['pax']);
}
return $filterSettings;
}
public static function fromRequest(Request $request): self
{
$requestArgument = $request->getArgument('filterSettings');
$filterSettings = is_array($requestArgument) ?
$requestArgument : json_decode($requestArgument, true, 512, JSON_THROW_ON_ERROR);
if ($requestArgument instanceof FilterSettings) {
$filterSettingsObject = $requestArgument;
} else {
$filterSettings['dateFrom'] = !empty($filterSettings['dateFrom']) ? new \DateTime($filterSettings['dateFrom']) : null;
$filterSettings['dateTo'] = !empty($filterSettings['dateTo']) ? new \DateTime($filterSettings['dateTo']) : null;
if (!empty($filterSettings['bus'])) {
$filterSettings['bus'] = \in_array($filterSettings['bus'], [ true, 'true', '1' ], true);
} else {
$filterSettings['bus'] = null;
}
$filterSettingsObject = new FilterSettings();
foreach ($filterSettings as $key => $value) {
$setter = 'set' . ucfirst($key);
$value = TypeConversionUtility::convertType($value);
if (method_exists($filterSettingsObject, $setter)) {
$filterSettingsObject->{$setter}($value);
}
}
}
return $filterSettingsObject;
}
/**
* @return array
*/
public function getPriceRanges()
{
return $this->priceRanges;
}
/**
* @param array $priceRanges
*/
public function setPriceRanges($priceRanges)
{
$this->priceRanges = $priceRanges;
}
/**
* @return array
*/
public function getCountryUids()
{
return $this->countryUids;
}
/**
* @param array $countryUids
*/
public function setCountryUids(?array $countryUids)
{
$this->countryUids = $countryUids;
}
/**
* @return array
*/
public function getRegionUids()
{
return $this->regionUids;
}
/**
* @param array $regionUids
*/
public function setRegionUids(?array $regionUids)
{
$this->regionUids = $regionUids;
}
/**
* @return array
*/
public function getCityUids()
{
return $this->cityUids;
}
/**
* @param array $cityUids
*/
public function setCityUids(?array $cityUids)
{
$this->cityUids = $cityUids;
}
/**
* @return array
*/
public function getConceptUids()
{
return $this->conceptUids;
}
/**
* @param array $conceptUids
*/
public function setConceptUids(?array $conceptUids)
{
$this->conceptUids = $conceptUids;
}
/**
* @return int
*/
public function getHotelUid()
{
return $this->hotelUid;
}
/**
* @param int $hotelUid
*/
public function setHotelUid($hotelUid)
{
$this->hotelUid = (int) $hotelUid;
}
/**
* @return int
*/
public function getProductUid()
{
return $this->productUid;
}
/**
* @param int $productUid
*/
public function setProductUid($productUid)
{
$this->productUid = (int) $productUid;
}
/**
* @return \DateTime
*/
public function getDateFrom()
{
return $this->dateFrom;
}
/**
* @param \DateTime $dateFrom
*/
public function setDateFrom(\DateTimeInterface $dateFrom = null)
{
$this->dateFrom = $dateFrom;
}
/**
* @return \DateTime
*/
public function getDateTo()
{
return $this->dateTo;
}
/**
* @param \DateTime $dateTo
*/
public function setDateTo(\DateTimeInterface $dateTo = null)
{
if ($this->dateFrom !== null && $dateTo !== null && $dateTo < $this->dateFrom) {
$dateTo = $this->dateFrom;
}
$this->dateTo = $dateTo;
}
/**
* @return int
*/
public function getNights() {
return $this->nights;
}
/**
* @param int $nights
*/
public function setNights($nights) {
$this->nights = (int) $nights;
}
/**
* @return int
*/
public function getPax() {
return $this->pax;
}
/**
* @param int $pax
*/
public function setPax($pax) {
$this->pax = (int) $pax;
}
/**
* @return array
*/
public function getBoardTypes()
{
return $this->boardTypes;
}
/**
* @param array $boardTypes
*/
public function setBoardTypes(?array $boardTypes)
{
$this->boardTypes = $boardTypes;
}
/**
* @return array
*/
public function getHotelTypes()
{
return $this->hotelTypes;
}
/**
* @param array $hotelTypes
*/
public function setHotelTypes(?array $hotelTypes)
{
$this->hotelTypes = $hotelTypes;
}
/**
* @return array
*/
public function getRoomTypes()
{
return $this->roomTypes;
}
/**
* @param array $roomTypes
*/
public function setRoomTypes(?array $roomTypes)
{
$this->roomTypes = $roomTypes;
}
/**
* @return bool
*/
public function getBus()
{
return $this->bus;
}
/**
* @param bool $bus
*/
public function setBus($bus)
{
$this->bus = $bus;
}
public function toArray(): array
{
return [
'priceRanges' => $this->getPriceRanges(),
'countryUids' => $this->getCountryUids(),
'regionUids' => $this->getRegionUids(),
'cityUids' => $this->getCityUids(),
'conceptUids' => $this->getConceptUids(),
'hotelUid' => $this->getHotelUid(),
'productUid' => $this->getProductUid(),
'nights' => $this->getNights(),
'pax' => $this->getPax(),
'boardTypes' => $this->getBoardTypes(),
'hotelTypes' => $this->getHotelTypes(),
'roomTypes' => $this->getRoomTypes(),
'dateFrom' => ($this->getDateFrom() !== null) ? $this->getDateFrom()->format('Y-m-d') : null,
'dateTo' => ($this->getDateTo() !== null) ? $this->getDateTo()->format('Y-m-d') : null,
'bus' => $this->getBus(),
];
}
public function jsonSerialize()
{
return $this->toArray();
}
}
@@ -1,297 +0,0 @@
<?php
namespace EP\EpProducts\Domain\Model;
/***************************************************************
*
* Copyright notice
*
* (c) 2017 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use EP\EpProducts\Utility\TypeConversionUtility;
use TYPO3\CMS\Extbase\Mvc\Request;
class SearchParams implements \JsonSerializable
{
public const DESTINATION_TYPE_COUNTRY = 'country';
public const DESTINATION_TYPE_REGION = 'region';
public const DESTINATION_TYPE_CITY = 'city';
public const DESTINATION_TYPE_CONCEPT = 'concept';
/**
* @var int
*/
protected $priceRange;
/**
* @var \DateTime
*/
protected $dateFrom;
/**
* @var \DateTime
*/
protected $dateTo;
/**
* @var int
*/
protected $destinationUid;
/**
* @var string
*/
protected $destinationType;
/**
* @var int
*/
protected $nights;
/**
* @var int
*/
protected $pax = 1;
/**
* @var int
*/
protected $pageUid;
/**
* @param int $pageUid
*/
public function __construct(int $pageUid = 0)
{
$this->setPageUid($pageUid);
}
public static function fromRequest(Request $request): self
{
$requestArgument = $request->getArgument('searchParams');
$searchParams = is_array($requestArgument) ?
$requestArgument : json_decode($requestArgument, true, 512, JSON_THROW_ON_ERROR);
$searchParams['dateFrom'] = !empty($searchParams['dateFrom']) ? new \DateTime($searchParams['dateFrom']) : null;
$searchParams['dateTo'] = !empty($searchParams['dateTo']) ? new \DateTime($searchParams['dateTo']) : null;
$searchParamsObject = new self;
foreach ($searchParams as $key => $value) {
$setter = 'set' . ucfirst($key);
$value = TypeConversionUtility::convertType($value);
if (method_exists($searchParamsObject, $setter)) {
$searchParamsObject->{$setter}($value);
}
}
return $searchParamsObject;
}
/**
* @return int
*/
public function getPriceRange()
{
return $this->priceRange;
}
/**
* @param int $priceRange
*/
public function setPriceRange($priceRange)
{
$this->priceRange = $priceRange;
}
/**
* @return \DateTime
*/
public function getDateFrom()
{
return $this->dateFrom;
}
/**
* @param \DateTime $dateFrom
*/
public function setDateFrom(\DateTime $dateFrom = null)
{
$this->dateFrom = $dateFrom;
}
/**
* @return \DateTime
*/
public function getDateTo()
{
return $this->dateTo;
}
/**
* @param \DateTime $dateTo
*/
public function setDateTo(\DateTime $dateTo = null)
{
$this->dateTo = $dateTo;
}
/**
* @return int
*/
public function getDestinationUid()
{
return $this->destinationUid;
}
/**
* @param int $destinationUid
*/
public function setDestinationUid($destinationUid)
{
$this->destinationUid = $destinationUid;
}
/**
* @return string
*/
public function getDestinationType()
{
return $this->destinationType;
}
/**
* @param string $destinationType
*/
public function setDestinationType($destinationType)
{
$this->destinationType = $destinationType;
}
/**
* @return int
*/
public function getNights()
{
return $this->nights;
}
/**
* @param int $nights
*/
public function setNights($nights)
{
$this->nights = $nights;
}
/**
* @return int
*/
public function getPax()
{
return $this->pax;
}
/**
* @param int $pax
*/
public function setPax($pax)
{
$this->pax = $pax;
}
/**
* @return int
*/
public function getPageUid()
{
return $this->pageUid;
}
/**
* @param int $pageUid
*/
public function setPageUid($pageUid)
{
$this->pageUid = $pageUid;
}
public function toFilterSettings(): array
{
$filterSettings = [];
if ($this->getDestinationType() && $this->getDestinationUid()) {
$destinationUid = $this->getDestinationUid();
switch ($this->getDestinationType()) {
case SearchParams::DESTINATION_TYPE_COUNTRY:
$filterSettings['countryUids'] = [ $destinationUid ];
break;
case SearchParams::DESTINATION_TYPE_REGION:
$filterSettings['regionUids'] = [ $destinationUid ];
break;
case SearchParams::DESTINATION_TYPE_CITY:
$filterSettings['cityUids'] = [ $destinationUid ];
break;
case SearchParams::DESTINATION_TYPE_CONCEPT:
$filterSettings['conceptUids'] = [ $destinationUid ];
break;
}
}
if (null !== $this->getDateFrom()) {
$filterSettings['dateFrom'] = $this->getDateFrom()->format('Y-m-d');
}
if (null !== $this->getDateTo()) {
$filterSettings['dateTo'] = $this->getDateTo()->format('Y-m-d');
}
if (null !== $this->getPriceRange()) {
$filterSettings['priceRanges'] = [ $this->getPriceRange() ];
}
if (null !== $this->getPax()) {
$filterSettings['pax'] = $this->getPax();
}
if (null !== $this->getNights()) {
$filterSettings['nights'] = $this->getNights();
}
return $filterSettings;
}
public function toArray(): array
{
return [
'priceRange' => $this->getPriceRange(),
'destinationUid' => $this->getDestinationUid(),
'destinationType' => $this->getDestinationType(),
'nights' => $this->getNights(),
'pax' => $this->getPax(),
'pageUid' => $this->getPageUid(),
'dateFrom' => ($this->getDateFrom() !== null) ? $this->getDateFrom()->format('Y-m-d') : null,
'dateTo' => ($this->getDateTo() !== null) ? $this->getDateTo()->format('Y-m-d') : null,
];
}
public function jsonSerialize()
{
return $this->toArray();
}
}
@@ -28,7 +28,7 @@ namespace EP\EpProducts\Domain\Repository;
***************************************************************/
use EP\EpProducts\Domain\Model\FilterOptions;
use EP\EpProducts\Domain\Model\FilterSettings;
use EP\EpProducts\Service\FilterService;
use EP\EpProducts\Traits\DbConnectionTrait;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
@@ -165,12 +165,12 @@ abstract class AbstractRepository extends \TYPO3\CMS\Extbase\Persistence\Reposit
return;
}
$nights = (int)$filterSettings['nights'];
if ($nights === FilterSettings::DURATION_SHORT) {
if ($nights === FilterService::DURATION_SHORT) {
$query
->andWhere('date.nights <= :nights')
->setParameter('nights', $nights)
;
} elseif ($nights === FilterSettings::DURATION_LONG) {
} elseif ($nights === FilterService::DURATION_LONG) {
$query
->andWhere('date.nights >= :nights')
->setParameter('nights', $nights)
@@ -27,7 +27,7 @@ namespace EP\EpProducts\Middleware;
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use EP\EpProducts\Domain\Model\FilterSettings;
use EP\EpProducts\Service\FilterService;
use EP\EpProducts\Service\FilterSettingsEncoder;
use EP\EpProducts\Traits\DbConnectionTrait;
use Psr\Http\Message\ResponseInterface;
@@ -36,6 +36,8 @@ use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use TYPO3\CMS\Core\Http\NormalizedParams;
use TYPO3\CMS\Core\Http\RedirectResponse;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Object\ObjectManager;
class StaticSearchParamsMiddleware implements MiddlewareInterface
{
@@ -78,8 +80,15 @@ class StaticSearchParamsMiddleware implements MiddlewareInterface
return $handler->handle($request);
}
$filterSettings = FilterSettings::fromStaticSearchParams($row);
$encodedFilterSettings = rawurlencode(FilterSettingsEncoder::encode($filterSettings));
/** @var \TYPO3\CMS\Extbase\Object\ObjectManager $objectManager */
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
/** @var \EP\EpProducts\Service\FilterService $filterService */
$filterService = $objectManager->get(FilterService::class);
$filterSettings = $filterService->getFilterSettingsFromStaticSearchParams($row);
$filterSettingsEncoder = new FilterSettingsEncoder();
$encodedFilterSettings = rawurlencode($filterSettingsEncoder->encode($filterSettings));
$redirectUri = self::SEARCH_RESULT_URI . $encodedFilterSettings . '/';
@@ -27,7 +27,6 @@ namespace EP\EpProducts\Service;
***************************************************************/
use EP\EpProducts\Domain\Model\Date;
use EP\EpProducts\Domain\Model\FilterSettings;
use EP\EpProducts\Domain\Model\Hotel;
use EP\EpProducts\Domain\Model\Product;
use EP\EpProducts\Domain\Repository\DateRepository;
@@ -112,7 +111,7 @@ class DateService implements SingletonInterface
$paCode = $resolvedOptions['paCode'];
if ($filterSettings === null) {
$filterSettings = $this->filterService->getDefaultFilterSettings();
$filterSettings = $this->filterService->getNormalizedFilterSettings();
}
$nonBookableDateUids = GeneralUtility::trimExplode(',', $product->getNonBookableDates(), true);
@@ -152,7 +151,7 @@ class DateService implements SingletonInterface
$paCode = $resolvedOptions['paCode'];
if ($filterSettings === null) {
$filterSettings = $this->filterService->getDefaultFilterSettings();
$filterSettings = $this->filterService->getNormalizedFilterSettings();
}
$nonBookableDateUids = GeneralUtility::trimExplode(',', $product->getNonBookableDates(), true);
@@ -196,67 +195,6 @@ class DateService implements SingletonInterface
]);
}
public function getAutocompleteOptions
(
FilterSettings $filterSettings,
string $search,
array $excludedConceptUids = [],
array $excludedRegionUids = []
)
{
$destinations = [
'country' => [
'label' => 'Länder',
'options' => [],
],
'region' => [
'label' => 'Gebiete',
'options' => [],
],
'city' => [
'label' => 'Orte',
'options' => [],
],
'hotel' => [
'label' => 'Unterkünfte',
'options' => [],
],
'product' => [
'label' => 'Reiseangebote',
'options' => [],
],
];
$search = mb_strtolower(trim($search));
foreach ($destinations as $type => $dummy) {
switch ($type) {
case 'hotel':
$result = $this->dateRepository->searchHotels($search, $filterSettings);
break;
case 'product':
$result = $this->dateRepository->searchProducts($search, $filterSettings, $excludedConceptUids);
break;
default:
$result = $this->dateRepository->searchDestinations(
$type,
$search,
$filterSettings,
$excludedRegionUids
);
}
foreach ($result as $row) {
$destinations[$type]['options'][] = [
'uid' => $row['uid'],
'name' => $row['name'],
];
}
}
return $destinations;
}
public function preprocessPriceTable(array $options): array
{
$resolver = new OptionsResolver();
@@ -28,8 +28,8 @@ namespace EP\EpProducts\Service;
***************************************************************/
use EP\EpProducts\Domain\Model\FilterOptions;
use EP\EpProducts\Domain\Model\FilterSettings;
use EP\EpProducts\Domain\Repository\DateRepository;
use Symfony\Component\OptionsResolver\OptionsResolver;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -37,6 +37,9 @@ use TYPO3\CMS\Core\Utility\PathUtility;
class FilterService implements SingletonInterface
{
public const DURATION_SHORT = 4;
public const DURATION_LONG = 5;
/**
* @var array
*/
@@ -55,29 +58,108 @@ class FilterService implements SingletonInterface
$this->dateRepository = $dateRepository;
}
public function getDefaultFilterSettings
(
array $forcedConceptUids = [],
bool $respectBookableDaterange = true,
string $dateFromYmd = null,
string $dateToYmd = null
): array {
$filterSettings = [];
public function getNormalizedFilterSettings(array $filterSettings = [], array $forcedConceptUids = []): array
{
$optionsResolver = new OptionsResolver();
$optionsResolver->setDefaults([
'priceRanges' => [],
'countryUids' => [],
'regionUids' => [],
'cityUids' => [],
'conceptUids' => [],
'boardTypes' => [],
'hotelTypes' => [],
'roomTypes' => [],
'hotelUid' => 0,
'productUid' => 0,
'dateFrom' => null,
'dateTo' => null,
'nights' => 0,
'pax' => 0,
'bus' => null,
]);
[ $dateFrom, $dateTo ] = $this->constrainDateRange($this->dateRepository->getDateRange());
$filterSettings = $optionsResolver->resolve($filterSettings);
if (null !== $dateFromYmd) {
$filterSettings['dateFrom'] = $dateFromYmd;
} elseif (!$respectBookableDaterange) {
$dateFrom = (new \DateTime('now'))->format('Y-m-d');
if (count($forcedConceptUids) > 0) {
array_push($filterSettings['conceptUids'], ...$forcedConceptUids);
}
if (null !== $dateToYmd) {
$filterSettings['dateTo'] = $dateToYmd;
return $filterSettings;
}
public function getFilterSettingsFromSearchParams(array $searchParams): array
{
$filterSettings = $this->getNormalizedFilterSettings();
if ($searchParams['destinationType'] && $searchParams['destinationUid']) {
switch ($searchParams['destinationType']) {
case SearchResultService::DESTINATION_TYPE_COUNTRY:
$filterSettings['countryUids'] = [ $searchParams['destinationUid'] ];
break;
case SearchResultService::DESTINATION_TYPE_REGION:
$filterSettings['regionUids'] = [ $searchParams['destinationUid'] ];
break;
case SearchResultService::DESTINATION_TYPE_CITY:
$filterSettings['cityUids'] = [ $searchParams['destinationUid'] ];
break;
case SearchResultService::DESTINATION_TYPE_CONCEPT:
$filterSettings['conceptUids'] = [ $searchParams['destinationUid'] ];
break;
}
}
if ($searchParams['dateFrom']) {
$filterSettings['dateFrom'] = $searchParams['dateFrom'];
}
if ($searchParams['dateTo']) {
$filterSettings['dateTo'] = $searchParams['dateTo'];
}
if ($searchParams['priceRange']) {
$filterSettings['priceRanges'] = [ $searchParams['priceRange'] ];
}
if ($searchParams['pax']) {
$filterSettings['pax'] = $searchParams['pax'];
}
if ($searchParams['nights']) {
$filterSettings['nights'] = $searchParams['nights'];
}
if ($forcedConceptUids) {
$filterSettings['conceptUids'] = $forcedConceptUids;
return $filterSettings;
}
public function getFilterSettingsFromStaticSearchParams(array $staticSearchParams): array
{
$filterSettings = $this->getNormalizedFilterSettings();
if (!empty($staticSearchParams['country'])) {
$filterSettings['countryUids'] = [ $staticSearchParams['country'] ];
}
if (!empty($staticSearchParams['region'])) {
$filterSettings['regionUids'] = [ $staticSearchParams['region'] ];
}
if (!empty($staticSearchParams['concept'])) {
$filterSettings['conceptUids'] = GeneralUtility::trimExplode(',', $staticSearchParams['concept'], true);
}
if (!empty($staticSearchParams['hotel'])) {
$filterSettings['hotelUid'] = $staticSearchParams['hotel'];
}
if (!empty($staticSearchParams['product'])) {
$filterSettings['productUid'] = $staticSearchParams['product'];
}
if (!empty($staticSearchParams['hotel_types'])) {
$filterSettings['hotelTypes'] = GeneralUtility::trimExplode(',', $staticSearchParams['hotel_types'], true);
}
if (!empty($staticSearchParams['bus'])) {
$filterSettings['bus'] = (bool)$staticSearchParams['bus'];
}
if (!empty($staticSearchParams['date_from']) && $staticSearchParams['date_from'] !== '0000-00-00') {
$filterSettings['dateFrom'] = $staticSearchParams['date_from'];
}
if (!empty($staticSearchParams['date_to']) && $staticSearchParams['date_to'] !== '0000-00-00') {
$filterSettings['dateTo'] = $staticSearchParams['date_to'];
}
if (!empty($staticSearchParams['pax']) && (int)$staticSearchParams['pax'] > 0) {
$filterSettings['pax'] = $staticSearchParams['pax'];
}
return $filterSettings;
@@ -118,8 +200,7 @@ class FilterService implements SingletonInterface
$absPath = ExtensionManagementUtility::extPath('ep_theme');
$baseUrl = '/' . PathUtility::stripPathSitePrefix($absPath);
foreach ($filterOptionsData as $row)
{
foreach ($filterOptionsData as $row) {
// Date
if (null === $dateMin || $row['dateStart'] < $dateMin) {
$dateMin = $row['dateStart'];
@@ -134,7 +215,7 @@ class FilterService implements SingletonInterface
}
// Nights
$duration = (int) $row['nights'] <= 4 ? FilterSettings::DURATION_SHORT : FilterSettings::DURATION_LONG;
$duration = (int) $row['nights'] <= 4 ? self::DURATION_SHORT : self::DURATION_LONG;
if (!\in_array($duration, $nights, false)) {
$nights[] = $duration;
@@ -235,25 +316,9 @@ class FilterService implements SingletonInterface
return $filterOptions;
}
public function constrainDateRange(array $dateRange, FilterSettings $filterSettings = null): array
{
[ $dateFrom, $dateTo ] = $dateRange;
if ($filterSettings !== null) {
$filterSettingsDateFrom = $filterSettings->getDateFrom();
if ($filterSettingsDateFrom !== null && $filterSettingsDateFrom > $dateFrom) {
$dateFrom = $filterSettings->getDateFrom();
}
$filterSettingsDateTo = $filterSettings->getDateTo();
if ($filterSettingsDateTo !== null && $filterSettingsDateTo < $dateTo) {
$dateTo = $filterSettings->getDateTo();
}
}
return [$dateFrom, $dateTo];
}
public function getFiltersettingsFromSettings(array $settings): array
{
$filterSettings = [];
$filterSettings = $this->getNormalizedFilterSettings();
if (isset($settings['regionUid']) && (int) $settings['regionUid'] > 0) {
$filterSettings['regionUids'] = [ $settings['regionUid'] ];
} elseif (isset($settings['countryUid']) && (int) $settings['countryUid'] > 0) {
@@ -34,7 +34,7 @@ class FilterSettingsEncoder
/**
* @return array
*/
protected static function getMapping()
protected function getMapping()
{
return [
[ 'countryUids', 'array' ],
@@ -54,10 +54,10 @@ class FilterSettingsEncoder
];
}
public static function encode(array $filterSettings): string
public function encode(array $filterSettings): string
{
$encoded = [];
foreach (static::getMapping() as $property) {
foreach ($this->getMapping() as $property) {
[$name, $type] = $property;
if (!isset($filterSettings[$name])) {
$encoded[] = '';
@@ -76,11 +76,11 @@ class FilterSettingsEncoder
return implode('|', $encoded);
}
public static function decode(string $data): array
public function decode(string $data): array
{
$decoded = [];
$values = explode('|', $data);
foreach (static::getMapping() as $index => $property)
foreach ($this->getMapping() as $index => $property)
{
[$name, $type] = $property;
$value = $values[$index];
@@ -26,7 +26,6 @@ namespace EP\EpProducts\Service;
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use EP\EpProducts\Domain\Model\FilterSettings;
use EP\EpProducts\Domain\Model\Hotel;
use EP\EpProducts\Domain\Repository\HotelRepository;
use EP\EpProducts\Domain\Repository\ProductRepository;
@@ -83,11 +82,11 @@ class ProductDataService implements SingletonInterface
}
/**
* @param FilterSettings $filterSettings
* @param array $filterSettings
*
* @return array
*/
public function getTeaser(FilterSettings $filterSettings)
public function getTeaser(array $filterSettings)
{
$teaserData = $this->productRepository->getTeasers($filterSettings);
$teasers = $this->preprocessTeasergroup($teaserData);
@@ -141,15 +140,12 @@ class ProductDataService implements SingletonInterface
$teaser['busIncluded'] = true;
}
$dateStart = new \DateTime($row['dateStart']);
$dateEnd = new \DateTime($row['dateEnd']);
if ($teaser['minDateStart'] === null || $teaser['minDateStart'] > $dateStart) {
$teaser['minDateStart'] = $dateStart;
if ($teaser['minDateStart'] === null || $teaser['minDateStart'] > $row['dateStart']) {
$teaser['minDateStart'] = $row['dateStart'];
}
if ($teaser['maxDateEnd'] === null || $teaser['maxDateEnd'] < $dateEnd) {
$teaser['maxDateEnd'] = $dateEnd;
if ($teaser['maxDateEnd'] === null || $teaser['maxDateEnd'] < $row['dateEnd']) {
$teaser['maxDateEnd'] = $row['dateEnd'];
}
if ($teaser['minPrice'] === null || $teaser['minPrice'] > $row['minPrice']) {
@@ -26,14 +26,19 @@ namespace EP\EpProducts\Service;
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use EP\EpProducts\Domain\Model\FilterSettings;
use EP\EpProducts\Domain\Model\Hotel;
use EP\EpProducts\Domain\Model\SearchResult;
use EP\EpProducts\Domain\Repository\ProductRepository;
use Symfony\Component\OptionsResolver\OptionsResolver;
use TYPO3\CMS\Core\SingletonInterface;
class SearchResultService implements SingletonInterface
{
public const DESTINATION_TYPE_COUNTRY = 'country';
public const DESTINATION_TYPE_REGION = 'region';
public const DESTINATION_TYPE_CITY = 'city';
public const DESTINATION_TYPE_CONCEPT = 'concept';
/**
* @var ProductRepository
*/
@@ -66,6 +71,23 @@ class SearchResultService implements SingletonInterface
$this->flagIconService = $flagIconService;
}
public function getNormalizedSearchParams(array $searchParams = []): array
{
$optionsResolver = new OptionsResolver();
$optionsResolver->setDefaults([
'priceRange' => null,
'dateFrom' => null,
'dateTo' => null,
'destinationUid' => null,
'destinationType' => null,
'nights' => null,
'pax' => 1,
'pageUid' => null,
]);
return $optionsResolver->resolve($searchParams);
}
public function getResult(array $filterSettings, array $excludedConceptUids = []): SearchResult
{
$searchResultData = $this->productRepository->getSearchResult($filterSettings, $excludedConceptUids);
@@ -1,96 +0,0 @@
<?php
namespace EP\EpProducts\Service;
/***************************************************************
*
* Copyright notice
*
* (c) 2018 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use EP\EpProducts\Domain\Model\SearchResult;
use Symfony\Component\OptionsResolver\OptionsResolver;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
class SearchResultUrlService implements SingletonInterface
{
/**
* @var UriBuilder
*/
protected $uriBuilder;
/**
* @param UriBuilder $uriBuilder
*/
public function __construct(UriBuilder $uriBuilder)
{
$this->uriBuilder = $uriBuilder;
}
/**
* @param SearchResult $searchResult
* @param int $defaultDetailPageUid
*/
public function process(SearchResult $searchResult, $defaultDetailPageUid): void
{
$data = $searchResult->getData();
foreach ($data as $conceptUid => $conceptData) {
foreach ($conceptData['items'] as $key => $item) {
$detailPageUid = $this->getProductPageUid($item['product']['detailPage'], $defaultDetailPageUid);
$arguments = [
'product' => $item['product']['uid'],
'hotel' => $item['hotel']['uid'],
];
$uri = $this
->uriBuilder
->reset()
->setTargetPageUid($detailPageUid)
->setCreateAbsoluteUri(true)
->uriFor('detail', $arguments, 'Product', 'epproducts', 'product_detail')
;
$data[$conceptUid]['items'][$key]['detailPageUri'] = $uri;
}
}
$searchResult->setData($data);
}
/**
* @param mixed $uid
* @param int $defaultUid
* @return int
*/
protected function getProductPageUid($uid, int $defaultUid): int
{
if (is_numeric($uid)) {
return (int) $uid;
}
if (strpos($uid, 't3://') !== false) {
parse_str(parse_url($uid, PHP_URL_QUERY), $arguments);
return (int) $arguments['uid'];
}
return $defaultUid;
}
}
@@ -27,9 +27,8 @@ namespace EP\EpProducts\Traits;
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use EP\EpProducts\Domain\Model\FilterSettings;
use EP\EpProducts\Domain\Model\SearchParams;
use EP\EpProducts\Service\FilterService;
use EP\EpProducts\Service\SearchResultService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Object\ObjectManager;
@@ -41,11 +40,22 @@ trait RequestArgumentTypeConversionTrait
*/
public function processSearchParamsArgument()
{
if ($this->request->hasArgument('searchParams')) {
$searchParamsObject = SearchParams::fromRequest($this->request);
/** @var \TYPO3\CMS\Extbase\Object\ObjectManager $objectManager */
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
$this->request->setArgument('searchParams', $searchParamsObject);
/** @var SearchResultService $searchResultService */
$searchResultService = $objectManager->get(SearchResultService::class);
if (!$this->request->hasArgument('searchParams')) {
$searchParams = $searchResultService->getNormalizedSearchParams();
} else {
$requestArgument = $this->request->getArgument('searchParams');
$searchParamsFromRequest = is_array($requestArgument) ?
$requestArgument : json_decode($requestArgument, true, 512, JSON_THROW_ON_ERROR);
$searchParams = $searchResultService->getNormalizedSearchParams($searchParamsFromRequest);
}
$this->request->setArgument('searchParams', $searchParams);
}
/**
@@ -61,18 +71,15 @@ trait RequestArgumentTypeConversionTrait
$filterService = $objectManager->get(FilterService::class);
if (!$this->request->hasArgument('filterSettings')) {
$filterSettingsObject = $filterService->getDefaultFilterSettings($forcedConceptUids);
$filterSettings = $filterService->getNormalizedFilterSettings([], $forcedConceptUids);
} else {
$filterSettingsObject = FilterSettings::fromRequest($this->request);
if ($forcedConceptUids) {
$conceptUids = $filterSettingsObject->getConceptUids();
array_push($conceptUids, ...$forcedConceptUids);
$filterSettingsObject->setConceptUids($conceptUids);
}
$requestArgument = $this->request->getArgument('filterSettings');
$filterSettingsFromRequest = is_array($requestArgument) ?
$requestArgument : json_decode($requestArgument, true, 512, JSON_THROW_ON_ERROR);
$filterSettings = $this->filterService->getNormalizedFilterSettings($filterSettingsFromRequest, $forcedConceptUids);
}
$this->request->setArgument('filterSettings', $filterSettingsObject);
$this->request->setArgument('filterSettings', $filterSettings);
}
}
@@ -28,7 +28,6 @@ namespace EP\EpTheme\ViewHelpers;
***************************************************************/
use EP\EpProducts\Service\FilterSettingsEncoder;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
@@ -69,8 +68,8 @@ class FilterSettingsEncoderViewHelper extends AbstractViewHelper
return '';
}
/** @var \EP\EpProducts\Service\FilterSettingsEncoder $encoder */
$encoder = GeneralUtility::makeInstance(FilterSettingsEncoder::class);
return $encoder::encode($argument);
$encoder = new FilterSettingsEncoder();
return $encoder->encode($argument);
}
}
@@ -21,6 +21,9 @@
</f:if>
</div>
<div class="searchresult__content">
<f:if condition="{referringPageUri}">
<f:variable name="referrer" value="{referringPageUri}"/>
</f:if>
<f:for each="{searchResult}" as="section">
<div id="concept-{section.concept.uid}">
<h2 class="headline headline--secondary headline--underlined">
@@ -31,7 +34,11 @@
<div class="teaserbox teaserbox--landscape teaserbox--searchresult searchresult-item">
<div class="teaserbox__image">
<img src="{item.country.flag}" class="teaserbox__flag" alt="{item.country.name}"/>
<a href="{item.detailPageUri}" rel="nofollow" title="Details &amp; Buchen">
<f:link.action action="detail" controller="Product" extensionName="epproducts" pluginName="product_detail"
arguments="{product: item.product.uid, hotel: item.hotel.uid}"
additionalParams="{ref: referrer}"
pageUid="{item.product.detailPage}" absolute="1"
rel="nofollow" title="Details &amp; Buchen">
<picture class="searchresult-item__image">
<source media="(min-width: 1201px)" data-srcset="{item.hotel.images.resized.m.0.url} 260w"/>
<source media="(max-width: 1200px)" data-srcset="{item.hotel.images.resized.l.0.url} 280w"/>
@@ -40,7 +47,7 @@
title="{item.hotel.images.resized.s.0.title}"
alt="{item.hotel.images.resized.s.0.alt}">
</picture>
</a>
</f:link.action>
<div class="concept-badge concept-badge--{section.concept.code}"
id="{section.concept.code}">
{section.concept.name}
@@ -106,11 +113,15 @@
<f:if condition="{item.dates -> f:count()} > 0">
<f:if condition="{item.daytrip}">
<f:else>
<a href="{item.detailPageUri}{f:if(condition: referringPageUri, then: '?ref={referringPageUri -> f:format.urlencode()}')}" rel="nofollow" title="Details &amp; Buchen">
<span class="searchresult-item__daterange">
<i class="fa fa-arrow-circle-right"></i> {item.dates -> f:count()} {f:if(condition: '{item.dates -> f:count()} > 1', then: 'Termine', else: 'Termin')}
</span>
</a>
<f:link.action action="detail" controller="Product" extensionName="epproducts" pluginName="product_detail"
arguments="{product: item.product.uid, hotel: item.hotel.uid}"
additionalParams="{ref: referrer}"
pageUid="{item.product.detailPage}" absolute="1"
rel="nofollow" title="Details &amp; Buchen">
<span class="searchresult-item__daterange">
<i class="fa fa-arrow-circle-right"></i> {item.dates -> f:count()} {f:if(condition: '{item.dates -> f:count()} > 1', then: 'Termine', else: 'Termin')}
</span>
</f:link.action>
</f:else>
</f:if>
</f:if>
@@ -121,10 +132,14 @@
</div>
<div class="teaserbox__aside__bottom">
<span class="searchresult-item__price">ab {item.minPrice} €</span>
<a href="{item.detailPageUri}{f:if(condition: referringPageUri, then: '?ref={referringPageUri -> f:format.urlencode()}')}" class="button button--full searchresult-item__button"
rel="nofollow" title="Details">
<f:link.action action="detail" controller="Product" extensionName="epproducts" pluginName="product_detail"
arguments="{product: item.product.uid, hotel: item.hotel.uid}"
additionalParams="{ref: referrer}"
pageUid="{item.product.detailPage}" absolute="1"
rel="nofollow" title="Details &amp; Buchen"
class="button w-full">
Details{f:if(condition: item.hideBookingButton, else: ' &amp; Buchen')}
</a>
</f:link.action>
</div>
</div>
<button class="teaserbox-watchlist" x-data="watchlistToggle('{item.key}')" x-bind="trigger">
@@ -10,6 +10,9 @@
</div>
</f:then>
<f:else>
<f:if condition="{referringPageUri}">
<f:variable name="referrer" value="{referringPageUri}"/>
</f:if>
<f:for each="{watchlist}" as="section">
<div id="concept-{section.concept.uid}">
<h2 class="headline headline--secondary headline--underlined">
@@ -20,7 +23,11 @@
<div class="teaserbox teaserbox--landscape teaserbox--searchresult searchresult-item">
<div class="teaserbox__image">
<img src="{item.country.flag}" class="teaserbox__flag" alt="{item.country.name}"/>
<a href="{item.detailPageUri}" rel="nofollow" title="Details &amp; Buchen">
<f:link.action action="detail" controller="Product" extensionName="epproducts" pluginName="product_detail"
arguments="{product: item.product.uid, hotel: item.hotel.uid}"
additionalParams="{ref: referrer}"
pageUid="{item.product.detailPage}" absolute="1"
rel="nofollow" title="Details &amp; Buchen">
<picture class="searchresult-item__image">
<source media="(min-width: 1201px)" data-srcset="{item.hotel.images.resized.m.0.url} 260w"/>
<source media="(max-width: 1200px)" data-srcset="{item.hotel.images.resized.l.0.url} 280w"/>
@@ -29,7 +36,7 @@
title="{item.hotel.images.resized.s.0.title}"
alt="{item.hotel.images.resized.s.0.alt}">
</picture>
</a>
</f:link.action>
<div class="concept-badge concept-badge--{section.concept.code}"
id="{section.concept.code}">
{section.concept.name}
@@ -95,11 +102,15 @@
<f:if condition="{item.dates -> f:count()} > 0">
<f:if condition="{item.daytrip}">
<f:else>
<a href="{item.detailPageUri}{f:if(condition: referringPageUri, then: '?ref={referringPageUri -> f:format.urlencode()}')}" rel="nofollow" title="Details &amp; Buchen">
<f:link.action action="detail" controller="Product" extensionName="epproducts" pluginName="product_detail"
arguments="{product: item.product.uid, hotel: item.hotel.uid}"
additionalParams="{ref: referrer}"
pageUid="{item.product.detailPage}" absolute="1"
rel="nofollow" title="Details &amp; Buchen">
<span class="searchresult-item__daterange">
<i class="fa fa-arrow-circle-right"></i> {item.dates -> f:count()} {f:if(condition: '{item.dates -> f:count()} > 1', then: 'Termine', else: 'Termin')}
</span>
</a>
</f:link.action>
</f:else>
</f:if>
</f:if>
@@ -110,10 +121,14 @@
</div>
<div class="teaserbox__aside__bottom">
<span class="searchresult-item__price">ab {item.minPrice} €</span>
<a href="{item.detailPageUri}{f:if(condition: referringPageUri, then: '?ref={referringPageUri -> f:format.urlencode()}')}" class="button button--full searchresult-item__button"
rel="nofollow" title="Details">
<f:link.action action="detail" controller="Product" extensionName="epproducts" pluginName="product_detail"
arguments="{product: item.product.uid, hotel: item.hotel.uid}"
additionalParams="{ref: referrer}"
pageUid="{item.product.detailPage}" absolute="1"
rel="nofollow" title="Details &amp; Buchen"
class="button w-full">
Details{f:if(condition: item.hideBookingButton, else: ' &amp; Buchen')}
</a>
</f:link.action>
</div>
</div>
<a href="#" class="teaserbox-watchlist" x-data="watchlistToggle('{item.key}')" x-bind="trigger">