refactor: remove code outside the first-goal scope
Keeps what the product detail pages, the AJAX date/price tables, the API endpoints (/api/hotel, /api/product, /api/content/*), the chatbot content-only page type and the MyE&P import need, determined by a class and template reference closure from those entry points. Removed: search, watchlist, calendar/contingent AJAX, snow report and contingent imports, groups swiss, iCal, reseller export, team/EpTeam, newsletter, CSV feeds, BpnConnect client, backend modules and page module previews, Tcemain hooks, scheduler tasks, staging and static search middlewares, forms and their finishers, gridelements and news templates, and the plugins and content elements not used on product pages. The SFTP and local XML import sources are gone; the import reads MyE&P only (ApiImportSource as ProductImportSource) and runs as ep:import-dates. ext_tables.sql stays complete so no table or column is dropped while the TYPO3 10 project shares the data. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
a46918de9d
commit
b890a55115
331 files changed
+18
-23190
No files matched your search
@@ -1,140 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\BpnConnect;
|
||||
|
||||
use Symfony\Component\HttpClient\HttpClient;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
class ApiClient
|
||||
{
|
||||
/**
|
||||
* Applied when extension configuration does not override them. Seconds.
|
||||
*/
|
||||
private const DEFAULT_TIMEOUT = 5;
|
||||
private const DEFAULT_MAX_DURATION = 15;
|
||||
|
||||
public const CALENDAR_MODE_DAYS = 'days';
|
||||
public const CALENDAR_MODE_RANGES = 'ranges';
|
||||
|
||||
private ?array $configuration = null;
|
||||
|
||||
public function getCalendar(
|
||||
$hotelCode,
|
||||
\DateTimeInterface $dateFrom,
|
||||
\DateTimeInterface $dateTo = null,
|
||||
string $mode = self::CALENDAR_MODE_DAYS
|
||||
): array {
|
||||
$query = [
|
||||
'hotelCode' => $hotelCode,
|
||||
'dateFrom' => $dateFrom->format('Y-m-d'),
|
||||
'mode' => $mode,
|
||||
];
|
||||
|
||||
if (null !== $dateTo) {
|
||||
$query['dateTo'] = $dateTo->format('Y-m-d');
|
||||
}
|
||||
|
||||
$response = $this->request('GET', 'api/v1/contingents/calendar', [
|
||||
'query' => $query,
|
||||
]);
|
||||
|
||||
$this->assertStatusCode($response, [Response::HTTP_OK], 'GET', 'api/v1/contingents/calendar');
|
||||
|
||||
return $this->decodeResponse($response, 'GET', 'api/v1/contingents/calendar');
|
||||
}
|
||||
|
||||
private function request(string $method, string $uri, array $options = []): ResponseInterface
|
||||
{
|
||||
try {
|
||||
return $this->getHttpClient()->request($method, $uri, $options);
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
throw new ApiException(sprintf('Bpn Connect API transport error for %s %s: %s', $method, $uri, $e->getMessage()), 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
private function assertStatusCode(ResponseInterface $response, array $expectedStatusCodes, string $method, string $uri): void
|
||||
{
|
||||
try {
|
||||
$statusCode = $response->getStatusCode();
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
throw new ApiException(sprintf('Bpn Connect API transport error while reading status for %s %s: %s', $method, $uri, $e->getMessage()), 0, $e);
|
||||
}
|
||||
|
||||
if (in_array($statusCode, $expectedStatusCodes, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new ApiException(sprintf('Bpn Connect API returned unexpected status %d for %s %s', $statusCode, $method, $uri), $statusCode);
|
||||
}
|
||||
|
||||
private function decodeResponse(ResponseInterface $response, string $method, string $uri): array
|
||||
{
|
||||
try {
|
||||
$data = $response->toArray(false);
|
||||
} catch (DecodingExceptionInterface $e) {
|
||||
throw new ApiException(sprintf('Bpn Connect API returned invalid JSON for %s %s: %s', $method, $uri, $e->getMessage()), 0, $e);
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
throw new ApiException(sprintf('Bpn Connect API transport error while reading body for %s %s: %s', $method, $uri, $e->getMessage()), 0, $e);
|
||||
}
|
||||
|
||||
if (!isset($data['data']) || !is_array($data['data'])) {
|
||||
throw new ApiException(sprintf('Bpn Connect API returned a calendar payload without a data array for %s %s', $method, $uri));
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function getHttpClient(): HttpClientInterface
|
||||
{
|
||||
$config = $this->getConfiguration();
|
||||
$baseUrl = trim((string)($config['bpnConnectApiBaseUrl'] ?? ''));
|
||||
$apiKey = trim((string)($config['bpnConnectApiKey'] ?? ''));
|
||||
|
||||
if ($baseUrl === '') {
|
||||
throw new ApiException('Bpn Connect API base URL is not configured.');
|
||||
}
|
||||
if ($apiKey === '') {
|
||||
throw new ApiException('Bpn Connect API key is not configured.');
|
||||
}
|
||||
|
||||
$options = [
|
||||
'headers' => [
|
||||
'X-API-KEY' => $apiKey,
|
||||
],
|
||||
];
|
||||
|
||||
// Without these the client falls back to PHP's default_socket_timeout (commonly 60s),
|
||||
// so a stalled API pins a PHP worker for a minute per request. The defaults live in
|
||||
// code rather than in ext_conf_template.txt: ExtensionConfiguration::get() returns the
|
||||
// stored configuration verbatim and only syncs the template when an extension has no
|
||||
// configuration at all, so a newly added template key is absent until someone saves
|
||||
// extension configuration by hand. Falling back to 0 there would silently mean "no
|
||||
// timeout" - the opposite of what this guard is for. An explicit 0 still disables.
|
||||
$timeout = (int)($config['bpnConnectApiTimeout'] ?? self::DEFAULT_TIMEOUT);
|
||||
if ($timeout > 0) {
|
||||
$options['timeout'] = $timeout;
|
||||
}
|
||||
$maxDuration = (int)($config['bpnConnectApiMaxDuration'] ?? self::DEFAULT_MAX_DURATION);
|
||||
if ($maxDuration > 0) {
|
||||
$options['max_duration'] = $maxDuration;
|
||||
}
|
||||
|
||||
return HttpClient::createForBaseUri(rtrim($baseUrl, '/') . '/', $options);
|
||||
}
|
||||
|
||||
private function getConfiguration(): array
|
||||
{
|
||||
if (null === $this->configuration) {
|
||||
$this->configuration = GeneralUtility::makeInstance(ExtensionConfiguration::class)
|
||||
->get('ep_products');
|
||||
}
|
||||
|
||||
return $this->configuration;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\BpnConnect;
|
||||
|
||||
class ApiException extends \RuntimeException
|
||||
{
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Command;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Service\ContingentImportService;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Object\ObjectManager;
|
||||
|
||||
class ContingentCommand extends Command
|
||||
{
|
||||
|
||||
/**
|
||||
* @var ContingentImportService
|
||||
*/
|
||||
protected $contingentImportService;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $defaultName = 'ep:contingent-import';
|
||||
|
||||
/**
|
||||
* @param ContingentImportService $contingentImportService
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
/** @var ObjectManager $objectManager */
|
||||
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
|
||||
$this->contingentImportService = $objectManager->get(ContingentImportService::class);
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$count = $this->contingentImportService->import();
|
||||
$output->writeln(sprintf('%d rows imported.', $count ));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,7 +28,7 @@ namespace EP\EpProducts\Command;
|
||||
***************************************************************/
|
||||
|
||||
use EP\EpProducts\Service\DateImportService;
|
||||
use EP\EpProducts\Service\ProductImportSourceFactory;
|
||||
use EP\EpProducts\Service\ProductImportSource;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
@@ -54,28 +54,28 @@ class DateCommandController extends Command
|
||||
protected $configurationManager;
|
||||
|
||||
/**
|
||||
* @var ProductImportSourceFactory
|
||||
* @var ProductImportSource
|
||||
*/
|
||||
protected $importSourceFactory;
|
||||
protected $importSource;
|
||||
|
||||
/**
|
||||
* @param DateImportService $importService
|
||||
* @param CacheService $cacheService
|
||||
* @param ConfigurationManagerInterface $configurationManager
|
||||
* @param ProductImportSourceFactory $importSourceFactory
|
||||
* @param ProductImportSource $importSource
|
||||
*/
|
||||
public function __construct
|
||||
(
|
||||
DateImportService $importService,
|
||||
CacheService $cacheService,
|
||||
ConfigurationManagerInterface $configurationManager,
|
||||
ProductImportSourceFactory $importSourceFactory
|
||||
ProductImportSource $importSource
|
||||
)
|
||||
{
|
||||
$this->dateImportService = $importService;
|
||||
$this->cacheService = $cacheService;
|
||||
$this->configurationManager = $configurationManager;
|
||||
$this->importSourceFactory = $importSourceFactory;
|
||||
$this->importSource = $importSource;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
@@ -87,15 +87,14 @@ class DateCommandController extends Command
|
||||
*/
|
||||
public function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$importSource = $this->importSourceFactory->get();
|
||||
$import = $importSource->acquire();
|
||||
$import = $this->importSource->acquire();
|
||||
if ($import === null) {
|
||||
$output->writeln('No new import available.');
|
||||
return 0;
|
||||
}
|
||||
|
||||
$count = $this->dateImportService->import($import->getRows());
|
||||
$importSource->markImported($import);
|
||||
$this->importSource->markImported($import);
|
||||
$output->writeln(sprintf('%d rows imported.', $count ));
|
||||
$settings = $this->getSettings();
|
||||
$resellerPageUid = $settings['resellerExportPageUid'];
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Command;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2019 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\CsvFormatter\FacebookCatalogCsvFormatter;
|
||||
use EP\EpProducts\CsvFormatter\GoogleBusinessFeedCsvFormatter;
|
||||
use EP\EpProducts\Domain\Model\Reseller;
|
||||
use EP\EpProducts\Domain\Repository\ResellerRepository;
|
||||
use EP\EpProducts\Service\ResellerDataService;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Serializer\Encoder\XmlEncoder;
|
||||
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Object\ObjectManager;
|
||||
|
||||
class ExportCommandController extends Command
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $imageDimensions = [
|
||||
'facebook' => [
|
||||
'width' => '1080',
|
||||
'maxHeight' => '1080',
|
||||
'cropVariant' => 'facebook',
|
||||
],
|
||||
'google' => [
|
||||
'width' => '1200',
|
||||
'maxHeight' => '1200',
|
||||
'cropVariant' => 'google',
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* @var ResellerRepository
|
||||
*/
|
||||
protected $resellerRepository;
|
||||
|
||||
/**
|
||||
* @var ResellerDataService
|
||||
*/
|
||||
protected $resellerDataService;
|
||||
|
||||
public function __construct(string $name = null)
|
||||
{
|
||||
parent::__construct($name);
|
||||
|
||||
/** @var ObjectManager $objectManager */
|
||||
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
|
||||
$this->resellerRepository = $objectManager->get(ResellerRepository::class);
|
||||
$this->resellerDataService = $objectManager->get(ResellerDataService::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$resellers = $this->resellerRepository->findAll();
|
||||
$destinationFolder = sprintf(
|
||||
'%s/fileadmin/reseller',
|
||||
\TYPO3\CMS\Core\Core\Environment::getPublicPath()
|
||||
);
|
||||
if (!file_exists($destinationFolder)) {
|
||||
mkdir($destinationFolder, 0755);
|
||||
}
|
||||
foreach ($resellers as $reseller) {
|
||||
/** @var Reseller $reseller */
|
||||
$output->writeln('Exporting XML for ' . $reseller->getName());
|
||||
$this->exportXml($reseller, $destinationFolder);
|
||||
$output->writeln('Exporting CSV (Facebook) for ' . $reseller->getName());
|
||||
$this->exportCsv($reseller, 'facebook', $destinationFolder);
|
||||
$output->writeln('Exporting CSV (Google) for ' . $reseller->getName());
|
||||
$this->exportCsv($reseller, 'google', $destinationFolder);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Reseller $reseller
|
||||
* @param string $destinationFolder
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
protected function exportXml(Reseller $reseller, $destinationFolder)
|
||||
{
|
||||
$myEpUrl = $this->getMyEpUrl();
|
||||
$data = $this->resellerDataService->preprocessAll($reseller, $myEpUrl);
|
||||
$encoders = [new XmlEncoder('products')];
|
||||
$normalizers = [new ObjectNormalizer()];
|
||||
$serializer = new Serializer($normalizers, $encoders);
|
||||
$xml = $serializer->serialize(
|
||||
$data,
|
||||
'xml',
|
||||
[ 'xml_encoding' => 'utf-8', 'xml_format_output' => false ]
|
||||
);
|
||||
$filename = sprintf(
|
||||
'%s/export_%s.xml',
|
||||
$destinationFolder,
|
||||
$reseller->getCode()
|
||||
);
|
||||
@unlink($filename);
|
||||
file_put_contents($filename, $xml);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Reseller $reseller
|
||||
* @param string $type
|
||||
* @param string $destinationFolder
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
protected function exportCsv(Reseller $reseller, $type, $destinationFolder)
|
||||
{
|
||||
$myEpUrl = $this->getMyEpUrl();
|
||||
$data = $this->resellerDataService->preprocessAll(
|
||||
$reseller,
|
||||
$myEpUrl,
|
||||
static::$imageDimensions[$type],
|
||||
$type
|
||||
);
|
||||
if ($type === 'google') {
|
||||
$csv = GoogleBusinessFeedCsvFormatter::format($data);
|
||||
} else {
|
||||
$csv = FacebookCatalogCsvFormatter::format($data);
|
||||
}
|
||||
$filename = sprintf(
|
||||
'%s/export_%s_%s.csv',
|
||||
$destinationFolder,
|
||||
$reseller->getCode(),
|
||||
$type
|
||||
);
|
||||
@unlink($filename);
|
||||
$fileHandle = fopen($filename, 'wb');
|
||||
foreach ($csv as $row) {
|
||||
fputcsv($fileHandle, $row);
|
||||
}
|
||||
fclose($fileHandle);
|
||||
}
|
||||
|
||||
protected function getMyEpUrl(): string
|
||||
{
|
||||
$config = GeneralUtility::makeInstance(ExtensionConfiguration::class)
|
||||
->get('ep_products');
|
||||
|
||||
return $config['myEpUrl'] ?? 'https://my.ep-reisen.de';
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Command;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2021 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\Service\GroupsSwissService;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Object\ObjectManager;
|
||||
|
||||
class GroupsSwissCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var GroupsSwissService
|
||||
*/
|
||||
private $groupsSwissService;
|
||||
|
||||
protected static $defaultName = 'ep:groups-swiss';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
/** @var ObjectManager $objectManager */
|
||||
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
|
||||
$this->groupsSwissService = $objectManager->get(GroupsSwissService::class);
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->addArgument(
|
||||
'hotel',
|
||||
InputArgument::REQUIRED,
|
||||
'E&P hotel uid'
|
||||
);
|
||||
$this->addArgument(
|
||||
'house',
|
||||
InputArgument::REQUIRED,
|
||||
'Groups.swiss house number'
|
||||
);
|
||||
$this->addArgument(
|
||||
'key',
|
||||
InputArgument::REQUIRED,
|
||||
'Groups.swiss API key'
|
||||
);
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$hotelUid = $input->getArgument('hotel');
|
||||
$houseNumber = $input->getArgument('house');
|
||||
$apiKey = $input->getArgument('key');
|
||||
|
||||
$success = $this->groupsSwissService->publishContingents($hotelUid, $houseNumber, $apiKey);
|
||||
|
||||
return $success ? 0 : 1;
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Command;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Service\SnowreportImportService;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class SnowreportCommandController extends Command
|
||||
{
|
||||
|
||||
/**
|
||||
* @var SnowreportImportService
|
||||
*/
|
||||
protected $snowreportImportService;
|
||||
|
||||
/**
|
||||
* @param SnowreportImportService $snowreportImportService
|
||||
*/
|
||||
public function __construct(SnowreportImportService $snowreportImportService)
|
||||
{
|
||||
$this->snowreportImportService = $snowreportImportService;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->snowreportImportService->downloadReportsXml();
|
||||
$count = $this->snowreportImportService->importSnowReportData();
|
||||
$output->writeln(sprintf('%d rows imported.', $count ));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,391 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\BpnConnect\ApiClient as BpnConnectClient;
|
||||
use EP\EpProducts\MyEP\ApiClient as MyEpClient;
|
||||
use EP\EpProducts\Domain\Model\Hotel;
|
||||
use EP\EpProducts\MyEP\ApiException;
|
||||
use EP\EpProducts\Utility\DateUtility;
|
||||
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
|
||||
|
||||
class AjaxCalendarController extends ActionController
|
||||
{
|
||||
private const CACHE_TTL = 3600;
|
||||
|
||||
protected BpnConnectClient $bpnConnectClient;
|
||||
protected MyEpClient $myEpClient;
|
||||
protected FrontendInterface $cache;
|
||||
|
||||
public function __construct(BpnConnectClient $bpnConnectClient, MyEpClient $myEpClient, FrontendInterface $cache)
|
||||
{
|
||||
$this->bpnConnectClient = $bpnConnectClient;
|
||||
$this->myEpClient = $myEpClient;
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
public function priceCalendarAction(Hotel $hotel, int $months = 12): void
|
||||
{
|
||||
$hotelCode = trim($hotel->getCode() ?? '');
|
||||
$this->tagPageCacheForHotel($hotelCode);
|
||||
|
||||
$dateRange = DateUtility::getDateRange(null, null, $months);
|
||||
$period = $dateRange['period'];
|
||||
$today = new \DateTimeImmutable('today');
|
||||
|
||||
$priceDataByDate = [];
|
||||
$error = false;
|
||||
$errorMessage = '';
|
||||
|
||||
if ($hotelCode !== '') {
|
||||
try {
|
||||
// This action is cacheable, so the rendered markup is held in the page cache
|
||||
// for config.cache_period. An additional application-level cache here would
|
||||
// key on exactly the same granularity (hotel + date range) and only stack a
|
||||
// second TTL on top, pushing worst-case staleness past the freshness budget.
|
||||
$rawData = $this->myEpClient->getPriceConfigData($hotelCode);
|
||||
|
||||
$availableDates = [];
|
||||
foreach ($rawData as $item) {
|
||||
if (($item['status'] ?? '') === 'OK') {
|
||||
$availableDates[$item['date']] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// The API no longer honours a date-range constraint, so it may return data
|
||||
// further out than the default $months grid covers. Grow the grid to match
|
||||
// whatever the API actually returned rather than silently dropping the tail.
|
||||
$lastDataDate = null;
|
||||
|
||||
foreach ($rawData as $item) {
|
||||
$date = $item['date'];
|
||||
$dt = \DateTimeImmutable::createFromFormat('Y-m-d', $date);
|
||||
if ($dt < $today) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (null === $lastDataDate || $dt > $lastDataDate) {
|
||||
$lastDataDate = $dt;
|
||||
}
|
||||
|
||||
$prevDate = $dt->modify('-1 day')->format('Y-m-d');
|
||||
$isAvailable = ($item['status'] ?? '') === 'OK';
|
||||
$prevAvailable = isset($availableDates[$prevDate]);
|
||||
|
||||
if ($isAvailable) {
|
||||
$dayStatus = $prevAvailable ? 'ok' : 'blocked-to-ok';
|
||||
} elseif ($prevAvailable) {
|
||||
$dayStatus = 'checkout-only';
|
||||
} else {
|
||||
$dayStatus = 'blocked';
|
||||
}
|
||||
|
||||
$priceDataByDate[$date] = [
|
||||
'status' => $dayStatus,
|
||||
'available' => $isAvailable ? 1 : 0,
|
||||
'tooltip' => $this->buildTooltip($dayStatus, $item),
|
||||
'pricePerNight' => $item['pricePerNight'] ?? null,
|
||||
'defaultPricePerNight' => $item['defaultPricePerNight'] ?? null,
|
||||
'type' => $item['type'] ?? null,
|
||||
'currency' => $item['currency'] ?? null,
|
||||
'includedPax' => $item['includedPax'] ?? null,
|
||||
'minNights' => (int)($item['minNights'] ?? 0),
|
||||
];
|
||||
}
|
||||
|
||||
if (null !== $lastDataDate) {
|
||||
$dataEnd = $lastDataDate->modify('first day of next month')->setTime(0, 0, 0);
|
||||
if ($dataEnd > $period->getEndDate()) {
|
||||
$period = new \League\Period\Period($period->getStartDate(), $dataEnd);
|
||||
}
|
||||
}
|
||||
} catch (ApiException $e) {
|
||||
$error = true;
|
||||
$errorMessage = $e->getMessage();
|
||||
$this->disablePageCache();
|
||||
}
|
||||
} else {
|
||||
$error = true;
|
||||
$errorMessage = 'Missing hotel code';
|
||||
$this->disablePageCache();
|
||||
}
|
||||
|
||||
$this->view->assignMultiple([
|
||||
'priceDataByDate' => $priceDataByDate,
|
||||
'calendarMonths' => $this->buildCalendarMonths($period),
|
||||
'error' => $error,
|
||||
'errorMessage' => $errorMessage,
|
||||
]);
|
||||
}
|
||||
|
||||
public function priceConfigAction(Hotel $hotel): void
|
||||
{
|
||||
$hotelCode = trim($hotel->getCode() ?? '');
|
||||
$this->tagPageCacheForHotel($hotelCode);
|
||||
|
||||
$priceConfig = [
|
||||
'data' => [],
|
||||
'success' => true,
|
||||
'error' => null,
|
||||
];
|
||||
|
||||
try {
|
||||
$priceConfig['data'] = $this->myEpClient->getPriceConfigData($hotelCode);
|
||||
} catch (ApiException $e) {
|
||||
$priceConfig['success'] = false;
|
||||
$priceConfig['error'] = $e->getMessage();
|
||||
$this->disablePageCache();
|
||||
}
|
||||
|
||||
$this->view->assign('priceConfig', $priceConfig);
|
||||
}
|
||||
|
||||
public function priceTableAction(Hotel $hotel, string $year = null): void
|
||||
{
|
||||
$year = $year ?? (new \DateTimeImmutable())->format('Y');
|
||||
$hotelCode = trim($hotel->getCode() ?? '');
|
||||
$this->tagPageCacheForHotel($hotelCode);
|
||||
|
||||
$priceTable = [
|
||||
'data' => [],
|
||||
'success' => true,
|
||||
'error' => null,
|
||||
];
|
||||
|
||||
try {
|
||||
$priceTable['data'] = $this->myEpClient->getPriceTableData($hotelCode, $year);
|
||||
} catch (ApiException $e) {
|
||||
$priceTable['success'] = false;
|
||||
$priceTable['error'] = $e->getMessage();
|
||||
$this->disablePageCache();
|
||||
}
|
||||
|
||||
$this->view->assignMultiple([
|
||||
'hotel' => $hotel,
|
||||
'year' => $year,
|
||||
'priceTable' => $priceTable,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Hotel $hotel
|
||||
* @param string $year
|
||||
* @param string $month
|
||||
* @param int $months
|
||||
*/
|
||||
public function rangeAction(Hotel $hotel, $year = null, $month = null, $months = 1)
|
||||
{
|
||||
$dateRange = DateUtility::getDateRange($year, $month, $months);
|
||||
$period = $dateRange['period'];
|
||||
$apiDateFrom = $dateRange['dateFrom'];
|
||||
$apiDateTo = $dateRange['dateTo'];
|
||||
$hotelCode = trim((string) $hotel->getCode());
|
||||
|
||||
$calendar = [
|
||||
'meta' => [],
|
||||
'data' => [],
|
||||
];
|
||||
|
||||
if ($hotelCode === '') {
|
||||
$calendar['error'] = true;
|
||||
} else {
|
||||
try {
|
||||
$cacheIdentifier = $this->getCacheIdentifier(
|
||||
$hotelCode,
|
||||
$apiDateFrom,
|
||||
$apiDateTo,
|
||||
BpnConnectClient::CALENDAR_MODE_DAYS
|
||||
);
|
||||
$cachedCalendar = $this->cache->get($cacheIdentifier);
|
||||
|
||||
if (false !== $cachedCalendar) {
|
||||
$calendar = $cachedCalendar;
|
||||
} else {
|
||||
$calendar = $this->bpnConnectClient->getCalendar(
|
||||
$hotelCode,
|
||||
new \DateTimeImmutable($apiDateFrom),
|
||||
new \DateTimeImmutable($apiDateTo),
|
||||
BpnConnectClient::CALENDAR_MODE_DAYS
|
||||
);
|
||||
$this->cache->set($cacheIdentifier, $calendar, [], self::CACHE_TTL);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$calendar['error'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
$this->view->assignMultiple([
|
||||
'months' => $months,
|
||||
'hotel' => $hotel,
|
||||
'calendar' => $calendar,
|
||||
'calendarMonths' => $this->buildCalendarMonths($period),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag this page-cache entry with the hotel it renders, so the entry can be flushed for
|
||||
* that hotel alone rather than by clearing the whole page cache and re-warming every
|
||||
* calendar. Tags are stored alongside the entry by
|
||||
* TypoScriptFrontendController::setPageCacheContent().
|
||||
*
|
||||
* Used manually today, when one hotel's availability needs re-fetching before its hour
|
||||
* is up:
|
||||
*
|
||||
* typo3cms cache:flushtags ep_hotel_<code> --groups pages
|
||||
*/
|
||||
private function tagPageCacheForHotel(string $hotelCode): void
|
||||
{
|
||||
if ('' === $hotelCode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($GLOBALS['TSFE']) && $GLOBALS['TSFE'] instanceof TypoScriptFrontendController) {
|
||||
$GLOBALS['TSFE']->addCacheTags(['ep_hotel_' . $hotelCode]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The calendar actions are cacheable, so an API failure would otherwise pin the error
|
||||
* markup in the page cache for the full cache_period. Drop caching for this request so
|
||||
* the next visitor gets a fresh attempt instead of an hour-old error message.
|
||||
*
|
||||
* The second argument must be true: set_no_cache() ignores the call otherwise, because
|
||||
* $TYPO3_CONF_VARS['FE']['disableNoCacheParameter'] defaults to true.
|
||||
*/
|
||||
private function disablePageCache(): void
|
||||
{
|
||||
if (isset($GLOBALS['TSFE']) && $GLOBALS['TSFE'] instanceof TypoScriptFrontendController) {
|
||||
$GLOBALS['TSFE']->set_no_cache('Price calendar data could not be retrieved', true);
|
||||
}
|
||||
}
|
||||
|
||||
private function buildTooltip(string $status, array $item): string
|
||||
{
|
||||
if ($status === 'blocked') {
|
||||
return 'Nicht verfügbar';
|
||||
}
|
||||
if ($status === 'checkout-only') {
|
||||
return 'Nur Abreise';
|
||||
}
|
||||
return $this->buildPriceTooltip($item);
|
||||
}
|
||||
|
||||
private function buildPriceTooltip(array $item): string
|
||||
{
|
||||
$price = $item['pricePerNight'] ?? null;
|
||||
$currency = $this->getCurrencySymbol($item['currency'] ?? null);
|
||||
|
||||
if ($price !== null) {
|
||||
$priceStr = (($item['type'] ?? null) === 'discount')
|
||||
? $price . ' ' . $currency
|
||||
: 'ab ' . $price . ' ' . $currency;
|
||||
} else {
|
||||
$priceStr = 'Anfrage';
|
||||
}
|
||||
|
||||
$minNights = (int)($item['minNights'] ?? 0);
|
||||
|
||||
return $minNights > 1
|
||||
? $priceStr . ' · min. ' . $minNights . ' Nächte'
|
||||
: $priceStr;
|
||||
}
|
||||
|
||||
private function getCurrencySymbol(?string $currency): string
|
||||
{
|
||||
if (null === $currency || '' === $currency) {
|
||||
return '€';
|
||||
}
|
||||
|
||||
return 'EUR' === $currency ? '€' : $currency;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
private function buildCalendarMonths(\League\Period\Period $period): array
|
||||
{
|
||||
$months = [];
|
||||
$current = new \DateTimeImmutable($period->getStartDate()->format('Y-m-01 00:00:00'));
|
||||
$lastDay = $period->getEndDate()->sub(new \DateInterval('P1D'));
|
||||
$lastMonthStart = new \DateTimeImmutable($lastDay->format('Y-m-01 00:00:00'));
|
||||
|
||||
while ($current <= $lastMonthStart) {
|
||||
$months[] = $this->buildCalendarMonth($current);
|
||||
$current = $current->modify('first day of next month');
|
||||
}
|
||||
|
||||
return $months;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function buildCalendarMonth(\DateTimeImmutable $monthStart): array
|
||||
{
|
||||
$firstOfMonth = $monthStart->setTime(0, 0, 0);
|
||||
$lastOfMonth = $firstOfMonth->modify('last day of this month');
|
||||
$gridStart = $firstOfMonth->modify('monday this week');
|
||||
$gridEnd = $lastOfMonth->modify('sunday this week');
|
||||
|
||||
$weeks = [];
|
||||
$week = [];
|
||||
$current = $gridStart;
|
||||
|
||||
while ($current <= $gridEnd) {
|
||||
$week[] = [
|
||||
'date' => $current,
|
||||
'inMonth' => $current->format('Y-m') === $firstOfMonth->format('Y-m'),
|
||||
];
|
||||
|
||||
if (count($week) === 7) {
|
||||
$weeks[] = $week;
|
||||
$week = [];
|
||||
}
|
||||
|
||||
$current = $current->add(new \DateInterval('P1D'));
|
||||
}
|
||||
|
||||
return [
|
||||
'date' => $firstOfMonth,
|
||||
'weeks' => $weeks,
|
||||
];
|
||||
}
|
||||
|
||||
private function getCacheIdentifier(string $hotelCode, string $dateFrom, string $dateTo, string $mode): string
|
||||
{
|
||||
return 'bpn_connect_calendar_' . sha1(implode('|', [
|
||||
$hotelCode,
|
||||
$dateFrom,
|
||||
$dateTo,
|
||||
$mode,
|
||||
]));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Domain\Model\Hotel;
|
||||
use EP\EpProducts\Domain\Model\Product;
|
||||
use EP\EpProducts\Domain\Repository\ContingentRepository;
|
||||
use EP\EpProducts\Service\ContingentDataService;
|
||||
use EP\EpProducts\Service\MyEpUrlResolverService;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
class AjaxContingentController extends ActionController
|
||||
{
|
||||
/**
|
||||
* @var \EP\EpProducts\Domain\Repository\ContingentRepository
|
||||
*/
|
||||
protected $contingentRepository;
|
||||
/**
|
||||
* @var ContingentDataService
|
||||
*/
|
||||
protected $contingentDataService;
|
||||
|
||||
/**
|
||||
* @var MyEpUrlResolverService
|
||||
*/
|
||||
protected $myEpUrlResolverService;
|
||||
|
||||
/**
|
||||
* @param ContingentRepository $contingentRepository
|
||||
* @param ContingentDataService $contingentDataService
|
||||
* @param MyEpUrlResolverService $myEpUrlResolverService
|
||||
*/
|
||||
public function __construct(
|
||||
ContingentRepository $contingentRepository,
|
||||
ContingentDataService $contingentDataService,
|
||||
MyEpUrlResolverService $myEpUrlResolverService
|
||||
) {
|
||||
$this->contingentRepository = $contingentRepository;
|
||||
$this->contingentDataService = $contingentDataService;
|
||||
$this->myEpUrlResolverService = $myEpUrlResolverService;
|
||||
}
|
||||
|
||||
public function initializeAction()
|
||||
{
|
||||
if ($this->request->hasArgument('dateFrom')) {
|
||||
$dateFrom = new \DateTime($this->request->getArgument('dateFrom'));
|
||||
$this->request->setArgument('dateFrom', $dateFrom);
|
||||
}
|
||||
if ($this->request->hasArgument('dateTo')) {
|
||||
$dateTo = new \DateTime($this->request->getArgument('dateTo'));
|
||||
$this->request->setArgument('dateTo', $dateTo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Hotel $hotel
|
||||
* @param Product $product
|
||||
* @param \DateTime $dateFrom
|
||||
* @param \DateTime $dateTo
|
||||
* @return string
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
public function roomsAction(Hotel $hotel, Product $product, \DateTime $dateFrom, \DateTime $dateTo)
|
||||
{
|
||||
$myEpUrl = $this->myEpUrlResolverService->resolve();
|
||||
$rooms = $this->contingentDataService->getAvailableRooms(
|
||||
$dateFrom->format('Y-m-d'),
|
||||
$dateTo->format('Y-m-d'),
|
||||
$hotel,
|
||||
$product,
|
||||
$myEpUrl
|
||||
);
|
||||
|
||||
return \json_encode($rooms);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Domain\Model\Hotel;
|
||||
use EP\EpProducts\Domain\Model\Product;
|
||||
use EP\EpProducts\Domain\Repository\ProductRepository;
|
||||
use EP\EpProducts\Service\DateService;
|
||||
use EP\EpProducts\Service\FilterService;
|
||||
use EP\EpProducts\Service\ResellerDataService;
|
||||
use EP\EpProducts\Traits\RequestArgumentTypeConversionTrait;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
|
||||
|
||||
class AjaxDateController extends ActionController
|
||||
{
|
||||
|
||||
use RequestArgumentTypeConversionTrait;
|
||||
|
||||
/**
|
||||
* @var \EP\EpProducts\Service\FilterService
|
||||
*/
|
||||
protected $filterService;
|
||||
|
||||
/**
|
||||
* @var DateService
|
||||
*/
|
||||
protected $dateService;
|
||||
|
||||
/**
|
||||
* @var ResellerDataService
|
||||
*/
|
||||
protected $resellerDataService;
|
||||
|
||||
/**
|
||||
* @var ProductRepository
|
||||
*/
|
||||
protected $productRepository;
|
||||
|
||||
/**
|
||||
* @param FilterService $filterService
|
||||
* @param DateService $dateService
|
||||
* @param ResellerDataService $resellerDataService
|
||||
* @param ProductRepository $productRepository
|
||||
*/
|
||||
public function __construct
|
||||
(
|
||||
FilterService $filterService,
|
||||
DateService $dateService,
|
||||
ResellerDataService $resellerDataService,
|
||||
ProductRepository $productRepository
|
||||
)
|
||||
{
|
||||
$this->filterService = $filterService;
|
||||
$this->dateService = $dateService;
|
||||
$this->resellerDataService = $resellerDataService;
|
||||
$this->productRepository = $productRepository;
|
||||
}
|
||||
|
||||
public function initializeDatesAction()
|
||||
{
|
||||
if ($this->request->hasArgument('dateFrom')) {
|
||||
$dateFrom = $this->request->getArgument('dateFrom');
|
||||
$this->request->setArgument('dateFrom', $dateFrom === '' ? null : $dateFrom);
|
||||
}
|
||||
if ($this->request->hasArgument('dateTo')) {
|
||||
$dateTo = $this->request->getArgument('dateTo');
|
||||
$this->request->setArgument('dateTo', $dateTo === '' ? null : $dateTo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Product $product
|
||||
* @param Hotel $hotel
|
||||
* @param string $paCode
|
||||
* @param string $dateFrom
|
||||
* @param string $dateTo
|
||||
*
|
||||
* @return string
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
public function datesAction(Product $product, Hotel $hotel = null, $paCode = null, $dateFrom = null, $dateTo = null)
|
||||
{
|
||||
$forcedConceptUids = GeneralUtility::trimExplode(',', $this->settings['forcedConceptUids'], true);
|
||||
$filterSettings = $this->filterService->getNormalizedFilterSettings([], $forcedConceptUids);
|
||||
$filterSettings['dateFrom'] = $dateFrom;
|
||||
$filterSettings['dateTo'] = $dateTo;
|
||||
|
||||
$altProductLink = null;
|
||||
$altLabel = null;
|
||||
if ($product->getAltProduct()) {
|
||||
$altProduct = $product->getAltProduct();
|
||||
if ($this->productRepository->hasDates($altProduct)) {
|
||||
/** @var ContentObjectRenderer $contentObject */
|
||||
$contentObject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
|
||||
$altProductLink = $contentObject->typoLink_URL(
|
||||
[
|
||||
'parameter' => $altProduct->getDetailPage(),
|
||||
]
|
||||
);
|
||||
$altLabel = $product->getAltLabel();
|
||||
}
|
||||
}
|
||||
$datesTable = $this->dateService->getDatesTable([
|
||||
'product' => $product,
|
||||
'hotel' => $hotel,
|
||||
'filterSettings' => $filterSettings,
|
||||
]);
|
||||
$hasSurchargeOrDiscount = $this->dateService->checkSurcharcheOrDiscount($datesTable);
|
||||
|
||||
return json_encode([
|
||||
'dates' => $datesTable,
|
||||
'bookable' => $product->getBookable(),
|
||||
'hotelName' => $hotel->getName(),
|
||||
'altProductLink' => $altProductLink,
|
||||
'altLabel' => $altLabel,
|
||||
'hasSurcharge' => $hasSurchargeOrDiscount['surcharge'],
|
||||
'hasDiscount' => $hasSurchargeOrDiscount['discount'],
|
||||
], JSON_THROW_ON_ERROR);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2021 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\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;
|
||||
|
||||
class AjaxFilterPanelController extends ActionController
|
||||
{
|
||||
|
||||
use RequestArgumentTypeConversionTrait;
|
||||
|
||||
/**
|
||||
* @var \EP\EpProducts\Service\FilterService
|
||||
*/
|
||||
protected $filterService;
|
||||
|
||||
/**
|
||||
* @var SearchResultService
|
||||
*/
|
||||
private $searchResultService;
|
||||
|
||||
/**
|
||||
* @param FilterService $filterService
|
||||
*/
|
||||
public function __construct(FilterService $filterService, SearchResultService $searchResultService)
|
||||
{
|
||||
$this->filterService = $filterService;
|
||||
$this->searchResultService = $searchResultService;
|
||||
}
|
||||
|
||||
public function initializeAction()
|
||||
{
|
||||
$forcedConceptUids = GeneralUtility::trimExplode(',', $this->settings['forcedConceptUids'], true);
|
||||
$this->processFilterSettingsArgument($forcedConceptUids);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $filterSettings
|
||||
*/
|
||||
public function indexAction(array $filterSettings)
|
||||
{
|
||||
$excludedConceptUids = GeneralUtility::trimExplode(',', $this->settings['excludedConceptUids']);
|
||||
|
||||
$searchResult = $this
|
||||
->searchResultService
|
||||
->getResult($filterSettings, $excludedConceptUids);
|
||||
|
||||
$filterOptions = $this->filterService->collectFilterOptionsFromSearchResult($searchResult);
|
||||
|
||||
$resultsUri = $this->uriBuilder
|
||||
->reset()
|
||||
->setCreateAbsoluteUri(true)
|
||||
->setTargetPageUid((int) $this->settings['defaultSearchPageUid'])
|
||||
->uriFor(
|
||||
'searchresult',
|
||||
['filterSettings' => $filterSettings],
|
||||
'Search',
|
||||
'epproducts',
|
||||
'searchresult'
|
||||
);
|
||||
|
||||
$filterOptions->setResultsUri($resultsUri);
|
||||
|
||||
$this->view->assignMultiple([
|
||||
'filterSettings' => $filterSettings,
|
||||
'filterOptions' => $filterOptions,
|
||||
'stimulusController' => 'mobile-search',
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Service\FilterService;
|
||||
use EP\EpProducts\Service\SearchResultService;
|
||||
use EP\EpProducts\Traits\RequestArgumentTypeConversionTrait;
|
||||
use EP\EpProducts\Utility\DateUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
class AjaxSearchController extends ActionController
|
||||
{
|
||||
|
||||
use RequestArgumentTypeConversionTrait;
|
||||
|
||||
/**
|
||||
* @var \EP\EpProducts\Service\FilterService
|
||||
*/
|
||||
protected $filterService;
|
||||
|
||||
/**
|
||||
* @var SearchResultService
|
||||
*/
|
||||
protected $searchResultService;
|
||||
|
||||
/**
|
||||
* @param FilterService $filterService
|
||||
* @param SearchResultService $searchResultService
|
||||
*/
|
||||
public function __construct(FilterService $filterService, SearchResultService $searchResultService)
|
||||
{
|
||||
$this->filterService = $filterService;
|
||||
$this->searchResultService = $searchResultService;
|
||||
}
|
||||
|
||||
public function initializeSearchresultAction()
|
||||
{
|
||||
$forcedConceptUids = GeneralUtility::intExplode(',', $this->settings['forcedConceptUids'], true);
|
||||
$this->processFilterSettingsArgument($forcedConceptUids);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $filterSettings
|
||||
*/
|
||||
public function searchresultAction(array $filterSettings): void
|
||||
{
|
||||
$dateSelected = false;
|
||||
$organic = true;
|
||||
$forcedConceptUids = GeneralUtility::intExplode(',', $this->settings['forcedConceptUids'], true);
|
||||
$excludedConceptUids = GeneralUtility::intExplode(',', $this->settings['excludedConceptUids'], true);
|
||||
|
||||
if (isset($filterSettings['dateFrom']) || isset($filterSettings['dateTo'])) {
|
||||
$dateSelected = true;
|
||||
}
|
||||
|
||||
$searchResult = $this
|
||||
->searchResultService
|
||||
->getResult($filterSettings, $excludedConceptUids);
|
||||
|
||||
// No results? First retry without date constraint if any
|
||||
if ((!empty($filterSettings['dateFrom']) || !empty($filterSettings['dateTo'])) && 0 === $searchResult->getTotal()) {
|
||||
$filterSettings['dateFrom'] = null;
|
||||
$filterSettings['dateTo'] = null;
|
||||
$searchResult = $this->searchResultService->getResult($filterSettings, $excludedConceptUids);
|
||||
$organic = false;
|
||||
}
|
||||
|
||||
// Still no results? Remove all constraints and search again with defaults
|
||||
if (0 === $searchResult->getTotal()) {
|
||||
$filterSettings = $this->filterService->getNormalizedFilterSettings([], $forcedConceptUids);
|
||||
$searchResult = $this->searchResultService->getResult($filterSettings, $excludedConceptUids);
|
||||
$organic = false;
|
||||
}
|
||||
|
||||
$filterOptions = $this->filterService->collectFilterOptionsFromSearchResult($searchResult);
|
||||
|
||||
$referringPageUri = $this
|
||||
->uriBuilder
|
||||
->reset()
|
||||
->setTargetPageUid((int)$this->settings['defaultSearchPageUid'])
|
||||
->setCreateAbsoluteUri(true)
|
||||
->uriFor(
|
||||
'searchresult',
|
||||
['filterSettings' => $filterSettings],
|
||||
'Search',
|
||||
'epproducts',
|
||||
'searchresult'
|
||||
)
|
||||
;
|
||||
|
||||
$this->view->assignMultiple([
|
||||
'filterSettings' => $filterSettings,
|
||||
'filterOptions' => $filterOptions,
|
||||
'searchResult' => $searchResult->getData(),
|
||||
'referringPageUri' => $referringPageUri,
|
||||
'stimulusController' => 'search',
|
||||
'meta' => [
|
||||
'organic' => $organic,
|
||||
'total' => $searchResult->getTotal(),
|
||||
'dateRange' => DateUtility::formatDateRange($filterSettings['dateFrom'], $filterSettings['dateTo']),
|
||||
'dateSelected' => $dateSelected,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Repository\ProductRepository;
|
||||
use EP\EpProducts\Service\FilterService;
|
||||
use EP\EpProducts\Service\SearchResultService;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
class AjaxWatchlistController extends ActionController
|
||||
{
|
||||
|
||||
/**
|
||||
* @var ProductRepository
|
||||
*/
|
||||
protected $productRepository;
|
||||
|
||||
/**
|
||||
* @var SearchResultService
|
||||
*/
|
||||
protected $searchResultService;
|
||||
|
||||
/**
|
||||
* @var FilterService
|
||||
*/
|
||||
protected $filterService;
|
||||
|
||||
/**
|
||||
* @param ProductRepository $productRepository
|
||||
* @param SearchResultService $searchResultService
|
||||
* @param FilterService $filterService
|
||||
*/
|
||||
public function __construct
|
||||
(
|
||||
ProductRepository $productRepository,
|
||||
SearchResultService $searchResultService,
|
||||
FilterService $filterService
|
||||
)
|
||||
{
|
||||
$this->productRepository = $productRepository;
|
||||
$this->searchResultService = $searchResultService;
|
||||
$this->filterService = $filterService;
|
||||
}
|
||||
|
||||
public function initializeAction()
|
||||
{
|
||||
if ($this->request->hasArgument('watchlistUids')) {
|
||||
$watchlistUids = json_decode($this->request->getArgument('watchlistUids'), true, 512, JSON_THROW_ON_ERROR);
|
||||
$this->request->setArgument('watchlistUids', $watchlistUids);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $watchlistUids
|
||||
* @return string
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
public function listAction(array $watchlistUids = [])
|
||||
{
|
||||
$productUids = array_map(function ($uid) {
|
||||
[ , $productUid ] = GeneralUtility::trimExplode(':', $uid);
|
||||
return $productUid;
|
||||
}, $watchlistUids);
|
||||
|
||||
$hotelUids = array_map(function ($uid) {
|
||||
[ $hotelUid, ] = GeneralUtility::trimExplode(':', $uid);
|
||||
return $hotelUid;
|
||||
}, $watchlistUids);
|
||||
|
||||
$watchlistData = $this->productRepository->getWatchlist($productUids, $hotelUids);
|
||||
$watchlist = $this->searchResultService->preprocess($watchlistData);
|
||||
|
||||
$this->view->assignMultiple([
|
||||
'watchlist' => $watchlist->getData(),
|
||||
'total' => $watchlist->getTotal()
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Service\ContingentImportService;
|
||||
use EP\EpProducts\Service\DateImportService;
|
||||
use EP\EpProducts\Service\ImportTimestampService;
|
||||
use EP\EpProducts\Service\LogService;
|
||||
use EP\EpProducts\Service\SnowreportImportService;
|
||||
use TYPO3\CMS\Backend\View\BackendTemplateView;
|
||||
use TYPO3\CMS\Core\Messaging\AbstractMessage;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
class BackendController extends ActionController
|
||||
{
|
||||
/**
|
||||
* @var BackendTemplateView
|
||||
*/
|
||||
protected $defaultViewObjectName = BackendTemplateView::class;
|
||||
|
||||
/**
|
||||
* @var BackendTemplateView
|
||||
*/
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* @var \EP\EpProducts\Service\DateImportService
|
||||
*/
|
||||
protected $dateImportService;
|
||||
|
||||
/**
|
||||
* @var \EP\EpProducts\Service\SnowreportImportService
|
||||
*/
|
||||
protected $snowreportImportService;
|
||||
|
||||
/**
|
||||
* @var \EP\EpProducts\Service\LogService
|
||||
*/
|
||||
protected $logService;
|
||||
|
||||
/**
|
||||
* @var ContingentImportService
|
||||
*/
|
||||
protected $contingentImportService;
|
||||
|
||||
/**
|
||||
* @param DateImportService $dateImportService
|
||||
* @param ContingentImportService $contingentImportService
|
||||
* @param SnowreportImportService $snowreportService
|
||||
* @param LogService $logService
|
||||
*/
|
||||
public function __construct
|
||||
(
|
||||
DateImportService $dateImportService,
|
||||
ContingentImportService $contingentImportService,
|
||||
SnowreportImportService $snowreportService,
|
||||
LogService $logService
|
||||
)
|
||||
{
|
||||
$this->dateImportService = $dateImportService;
|
||||
$this->contingentImportService = $contingentImportService;
|
||||
$this->snowreportImportService = $snowreportService;
|
||||
$this->logService = $logService;
|
||||
}
|
||||
|
||||
public function indexAction()
|
||||
{
|
||||
$timestampService = new ImportTimestampService();
|
||||
|
||||
$productDataUpdatedTimestamp = $timestampService->readImportTimestamp('fileadmin/products_import.info');
|
||||
$contingentsDataUpdatedTimestamp = $timestampService->readImportTimestamp('fileadmin/contingents_import.info');
|
||||
|
||||
$this->view->assign('productDataUpdatedTimestamp', $productDataUpdatedTimestamp);
|
||||
$this->view->assign('contingentsDataUpdatedTimestamp', $contingentsDataUpdatedTimestamp);
|
||||
}
|
||||
|
||||
public function importSnowReportAction()
|
||||
{
|
||||
$this->snowreportImportService->downloadReportsXml();
|
||||
$count = $this->snowreportImportService->importSnowReportData();
|
||||
$this->addFlashMessage($count . ' Datensätze importiert', 'Import abgechlossen', AbstractMessage::OK);
|
||||
$this->redirect('index');
|
||||
}
|
||||
|
||||
public function dumpSearchLogEpreisenAction()
|
||||
{
|
||||
$csv = $this->logService->dumpSearchLogEpreisen();
|
||||
$this->dumpSearchLog($csv, 'epreisen');
|
||||
}
|
||||
|
||||
public function dumpSearchLogEpeventsAction()
|
||||
{
|
||||
$csv = $this->logService->dumpSearchLogEpevents();
|
||||
$this->dumpSearchLog($csv, 'epevents');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $csv
|
||||
* @param $name
|
||||
*/
|
||||
private function dumpSearchLog(array $csv, $name)
|
||||
{
|
||||
$fileName = sprintf('searchlog_dump_%s_%s.csv', $name, date('dmY'));
|
||||
|
||||
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
|
||||
header('Content-Description: File Transfer');
|
||||
header('Content-type: text/csv');
|
||||
header("Content-Disposition: attachment; filename={$fileName}");
|
||||
header('Expires: 0');
|
||||
header('Pragma: public');
|
||||
|
||||
$fh = @fopen( 'php://output', 'wb' );
|
||||
|
||||
foreach ($csv as $data) {
|
||||
fputcsv($fh, $data, ';');
|
||||
}
|
||||
|
||||
fclose($fh);
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Domain\Model\City;
|
||||
use EP\EpProducts\Domain\Repository\CityRepository;
|
||||
use EP\EpProducts\Service\ProductDataService;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
class CityController extends ActionController
|
||||
{
|
||||
|
||||
/**
|
||||
* @var CityRepository
|
||||
*/
|
||||
protected $cityRepository;
|
||||
|
||||
/**
|
||||
* @var ProductDataService
|
||||
*/
|
||||
private $productDataService;
|
||||
|
||||
/**
|
||||
* @param CityRepository $cityRepository
|
||||
* @param ProductDataService $productDataService
|
||||
*/
|
||||
public function __construct(CityRepository $cityRepository, ProductDataService $productDataService)
|
||||
{
|
||||
$this->cityRepository = $cityRepository;
|
||||
$this->productDataService = $productDataService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param City $city
|
||||
*/
|
||||
public function detailAction(City $city = null): void
|
||||
{
|
||||
if (null === $city) {
|
||||
$cityUid = $this->settings['cityUid'];
|
||||
$city = $this->cityRepository->findByIdentifier($cityUid);
|
||||
}
|
||||
|
||||
$teasers = [];
|
||||
|
||||
if (null !== $city) {
|
||||
$filterSettings = [
|
||||
'cityUids' => [$cityUid]
|
||||
];
|
||||
$teasers = $this->productDataService->getTeasergroup($filterSettings);
|
||||
}
|
||||
|
||||
$this->view->assignMultiple([
|
||||
'city' => $city,
|
||||
'teasers' => $teasers,
|
||||
'filterSettings' => $filterSettings,
|
||||
]);
|
||||
}
|
||||
|
||||
public function teasergroupAction(): void
|
||||
{
|
||||
$regionUid = (int)$this->settings['regionUid'];
|
||||
$countryUid = (int)$this->settings['countryUid'];
|
||||
$season = $this->settings['season'];
|
||||
$citiesPid = (int)$this->settings['citiesStoragePid'];
|
||||
|
||||
$cities = $this->cityRepository->getTeasersByCountryOrRegionAndSeason($regionUid, $countryUid, $season, $citiesPid);
|
||||
$data = $this->configurationManager->getContentObject()->data;
|
||||
$this->view->assign('data', $data);
|
||||
$this->view->assign('teasers', $cities);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Domain\Model\Concept;
|
||||
use EP\EpProducts\Domain\Repository\ConceptRepository;
|
||||
use EP\EpProducts\Service\ProductDataService;
|
||||
use EP\EpTheme\Domain\Repository\PageRepository;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
class ConceptController extends ActionController
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \EP\EpProducts\Domain\Repository\ConceptRepository
|
||||
*/
|
||||
protected $conceptRepository;
|
||||
|
||||
/**
|
||||
* @var \EP\EpProducts\Service\ProductDataService
|
||||
*/
|
||||
protected $productDataService;
|
||||
|
||||
/**
|
||||
* @var \EP\EpTheme\Domain\Repository\PageRepository
|
||||
*/
|
||||
private $pageRepository;
|
||||
|
||||
/**
|
||||
* @param ConceptRepository $conceptRepository
|
||||
* @param ProductDataService $productDataService
|
||||
* @param PageRepository $pageRepository
|
||||
*/
|
||||
public function __construct(ConceptRepository $conceptRepository, ProductDataService $productDataService, PageRepository $pageRepository)
|
||||
{
|
||||
$this->conceptRepository = $conceptRepository;
|
||||
$this->productDataService = $productDataService;
|
||||
$this->pageRepository = $pageRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Concept $concept
|
||||
*/
|
||||
public function detailAction(Concept $concept = null)
|
||||
{
|
||||
if ($concept === null) {
|
||||
$conceptUid = $this->settings['conceptUid'];
|
||||
$concept = $this->conceptRepository->findByIdentifier($conceptUid);
|
||||
}
|
||||
|
||||
$teaserConceptUids = GeneralUtility::trimExplode(',', $this->settings['additionalConceptUids']);
|
||||
if (null !== $concept) {
|
||||
array_unshift($teaserConceptUids, $concept->getUid());
|
||||
}
|
||||
|
||||
$filterSettings = ['conceptUids' => $teaserConceptUids];
|
||||
$excludedConceptUids = GeneralUtility::trimExplode(',', $this->settings['excludedConceptUids'], true);
|
||||
$limit = $this->settings['showMoreLink'] ? 6 : 0;
|
||||
$teasers = $this->productDataService->getTeasergroup($filterSettings, $excludedConceptUids, $limit);
|
||||
$pages = $this->pageRepository->findPagesByPid((int)$this->settings['conceptsPageUid']);
|
||||
$data = $this->configurationManager->getContentObject()->data;
|
||||
|
||||
$this->view->assignMultiple([
|
||||
'teasers' => $teasers,
|
||||
'concept' => $concept,
|
||||
'filterSettings' => $filterSettings,
|
||||
'pages' => $pages,
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function teasergroupAction()
|
||||
{
|
||||
$concepts = $this->conceptRepository->findAll();
|
||||
$this->view->assign('teasers', $concepts);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Domain\Model\Country;
|
||||
use EP\EpProducts\Domain\Repository\CountryRepository;
|
||||
use EP\EpProducts\Service\ProductDataService;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
class CountryController extends ActionController
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \EP\EpProducts\Domain\Repository\CountryRepository
|
||||
*/
|
||||
protected $countryRepository;
|
||||
|
||||
/**
|
||||
* @var ProductDataService
|
||||
*/
|
||||
protected $productDataService;
|
||||
|
||||
/**
|
||||
* @param CountryRepository $countryRepository
|
||||
* @param ProductDataService $productDataService
|
||||
*/
|
||||
public function __construct(CountryRepository $countryRepository, ProductDataService $productDataService)
|
||||
{
|
||||
$this->countryRepository = $countryRepository;
|
||||
$this->productDataService = $productDataService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Country $country
|
||||
*/
|
||||
public function detailAction(Country $country = null)
|
||||
{
|
||||
if ($country === null) {
|
||||
$countryUid = $this->settings['countryUid'];
|
||||
$country = $this->countryRepository->findByIdentifier($countryUid);
|
||||
}
|
||||
$filterSettings = [
|
||||
'countryUids' => [ $countryUid ],
|
||||
];
|
||||
$excludedConceptUids = GeneralUtility::trimExplode(',', $this->settings['excludedConceptUids'], true);
|
||||
$limit = $this->settings['showMoreLink'] ? 6 : 0;
|
||||
$teasers = $this->productDataService->getTeasergroup($filterSettings, $excludedConceptUids, $limit);
|
||||
$this->view->assign('teasers', $teasers);
|
||||
$this->view->assign('country', $country);
|
||||
$this->view->assign('filterSettings', $filterSettings);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Domain\Repository\FaqRepository;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
class FaqController extends ActionController
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \EP\EpProducts\Domain\Repository\FaqRepository
|
||||
*/
|
||||
protected $faqRepository;
|
||||
|
||||
/**
|
||||
* @param FaqRepository $faqRepository
|
||||
*/
|
||||
public function __construct(FaqRepository $faqRepository)
|
||||
{
|
||||
$this->faqRepository = $faqRepository;
|
||||
}
|
||||
|
||||
public function detailAction()
|
||||
{
|
||||
$faqUids = $this->settings['faqUids'];
|
||||
$faqs = $this->faqRepository->findByUids($faqUids);
|
||||
$this->view->assign('faqs', $faqs);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Domain\Model\Hotel;
|
||||
use EP\EpProducts\Domain\Repository\HotelRepository;
|
||||
use EP\EpProducts\Domain\Repository\ProductRepository;
|
||||
use EP\EpProducts\Service\HotelDataService;
|
||||
use EP\EpProducts\Service\ProductDataService;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
class HotelController extends ActionController
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \EP\EpProducts\Domain\Repository\HotelRepository
|
||||
*/
|
||||
protected $hotelRepository;
|
||||
|
||||
/**
|
||||
* @var \EP\EpProducts\Domain\Repository\ProductRepository
|
||||
*/
|
||||
protected $productRepository;
|
||||
|
||||
/**
|
||||
* @var \EP\EpProducts\Service\HotelDataService
|
||||
*/
|
||||
protected $hotelDataService;
|
||||
|
||||
/**
|
||||
* @var ProductDataService
|
||||
*/
|
||||
protected $productDataService;
|
||||
|
||||
/**
|
||||
* @param HotelDataService $hotelDataService
|
||||
* @param HotelRepository $hotelRepository
|
||||
* @param ProductRepository $productRepository
|
||||
* @param ProductDataService $productDataService
|
||||
*/
|
||||
public function __construct
|
||||
(
|
||||
HotelDataService $hotelDataService,
|
||||
HotelRepository $hotelRepository,
|
||||
ProductRepository $productRepository,
|
||||
ProductDataService $productDataService
|
||||
)
|
||||
{
|
||||
$this->hotelRepository = $hotelRepository;
|
||||
$this->productRepository = $productRepository;
|
||||
$this->hotelDataService = $hotelDataService;
|
||||
$this->productDataService = $productDataService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Hotel $hotel
|
||||
*/
|
||||
public function detailAction(Hotel $hotel = null)
|
||||
{
|
||||
if ($hotel !== null) {
|
||||
$hotelUid = $hotel->getUid();
|
||||
} else {
|
||||
$hotelUid = $this->settings['hotelUid'];
|
||||
/** @var Hotel $hotel */
|
||||
$hotel = $this->hotelRepository->findByIdentifier($hotelUid);
|
||||
}
|
||||
$filterSettings = [
|
||||
'hotelUid' => $hotelUid,
|
||||
];
|
||||
$excludedConceptUids = GeneralUtility::trimExplode(',', $this->settings['excludedConceptUids'], true);
|
||||
$limit = $this->settings['hideMoreLink'] ? 0 : 6;
|
||||
$teasers = $this->productDataService->getTeasergroup($filterSettings, $excludedConceptUids, $limit);
|
||||
$this->view->assign('hotel', $hotel);
|
||||
$this->view->assign('teasers', $teasers);
|
||||
$this->view->assign('filterSettings', $filterSettings);
|
||||
}
|
||||
|
||||
public function detailEventAction()
|
||||
{
|
||||
$productUid = $this->settings['productUid'];
|
||||
/** @var \EP\EpProducts\Domain\Model\Product $product */
|
||||
$product = $this->productRepository->findByIdentifier($productUid);
|
||||
$hotelUid = $this->settings['hotelUid'];
|
||||
/** @var \EP\EpProducts\Domain\Model\Hotel $hotel */
|
||||
$hotel = $this->hotelRepository->findByIdentifier($hotelUid);
|
||||
$this->view->assignMultiple([
|
||||
'product' => $product,
|
||||
'hotel' => $hotel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function teasergroupAction()
|
||||
{
|
||||
$criteria = [
|
||||
'regionUid' => (int) $this->settings['regionUid'],
|
||||
'countryUid' => (int) $this->settings['countryUid'],
|
||||
'conceptUid' => (int) $this->settings['conceptUid'],
|
||||
'productUid' => (int) $this->settings['productUid'],
|
||||
'category' => (int) $this->settings['category'],
|
||||
'type' => (int) $this->settings['type'],
|
||||
];
|
||||
$bookable = $this->hotelDataService->getTeasersByCriteria($criteria);
|
||||
$bookableHotelUids = array_keys($bookable);
|
||||
$nonBookable = $this->hotelDataService->getDateIndependentTeasersByCriteria($criteria, $bookableHotelUids);
|
||||
$data = $this->configurationManager->getContentObject()->data;
|
||||
$this->view->assign('data', $data);
|
||||
$this->view->assign('bookable', $bookable);
|
||||
$this->view->assign('nonBookable', $nonBookable);
|
||||
}
|
||||
|
||||
public function dateIndependentTeasergroupAction()
|
||||
{
|
||||
$criteria = [
|
||||
'regionUid' => (int) $this->settings['regionUid'],
|
||||
'countryUid' => (int) $this->settings['countryUid'],
|
||||
'productUid' => (int) $this->settings['productUid'],
|
||||
'category' => (int) $this->settings['category'],
|
||||
'type' => (int) $this->settings['type'],
|
||||
];
|
||||
$hotels = $this->hotelDataService->getDateIndependentTeasersByCriteria($criteria);
|
||||
$data = $this->configurationManager->getContentObject()->data;
|
||||
$this->view->assign('data', $data);
|
||||
$this->view->assign('teasers', $hotels);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2019 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\Hotel;
|
||||
use EP\EpProducts\Service\IcalService;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
class IcalController extends ActionController
|
||||
{
|
||||
/**
|
||||
* @var IcalService
|
||||
*/
|
||||
protected $icalService;
|
||||
|
||||
public function __construct(IcalService $icalService)
|
||||
{
|
||||
$this->icalService = $icalService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Hotel $hotel
|
||||
* @return string
|
||||
*/
|
||||
public function contingentsAction(Hotel $hotel)
|
||||
{
|
||||
header(sprintf('Content-disposition: attachment; filename=%s.ical', $hotel->getPathSegment()));
|
||||
|
||||
return $this->icalService->createContingentsFeed($hotel);
|
||||
}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Domain\Repository\HotelRepository;
|
||||
use EP\EpProducts\Domain\Repository\ProductRepository;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
|
||||
|
||||
class MapController extends ActionController
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \EP\EpProducts\Domain\Repository\HotelRepository
|
||||
*/
|
||||
protected $hotelRepository;
|
||||
|
||||
/**
|
||||
* @var \EP\EpProducts\Domain\Repository\ProductRepository
|
||||
*/
|
||||
protected $productRepository;
|
||||
|
||||
/**
|
||||
* @param HotelRepository $hotelRepository
|
||||
* @param ProductRepository $productRepository
|
||||
*/
|
||||
public function __construct(
|
||||
HotelRepository $hotelRepository,
|
||||
ProductRepository $productRepository
|
||||
)
|
||||
{
|
||||
$this->hotelRepository = $hotelRepository;
|
||||
$this->productRepository = $productRepository;
|
||||
}
|
||||
|
||||
public function generalAction()
|
||||
{
|
||||
$markerData = [];
|
||||
$selectedHotels = $this->settings['hotelUids'];
|
||||
$hotelUids = GeneralUtility::trimExplode(',', $selectedHotels);
|
||||
$hotels = $this->hotelRepository->getListByUids($hotelUids);
|
||||
if ($hotels) {
|
||||
foreach ($hotels as $hotel)
|
||||
{
|
||||
/** @var \EP\EpProducts\Domain\Model\Hotel $hotel */
|
||||
$markerData[] = [
|
||||
'name' => $hotel->getName(),
|
||||
'uri' => $this->getUriForPageUid($hotel->getDetailPage()),
|
||||
'teaser' => $hotel->getTeaser(),
|
||||
'lat' => $hotel->getLatitude(),
|
||||
'lng' => $hotel->getLongitude(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$selectedProducts = $this->settings['productUids'];
|
||||
$productUids = GeneralUtility::trimExplode(',', $selectedProducts);
|
||||
$products = $this->productRepository->getListByUids($productUids);
|
||||
if ($products) {
|
||||
foreach ($products as $product)
|
||||
{
|
||||
/** @var \EP\EpProducts\Domain\Model\Product $product */
|
||||
$hotel = $product->getHotels()->current();
|
||||
if (null === $hotel || false === $hotel->isShowAsTeaser()) {
|
||||
continue;
|
||||
}
|
||||
$markerData[] = [
|
||||
'name' => $product->getName(),
|
||||
'uri' => $this->getUriForPageUid($product->getDetailPage()),
|
||||
'externalLink' => $hotel->getExternalLink(),
|
||||
'teaser' => preg_replace("/[\r\n\t]/", "", $product->getTeaser()),
|
||||
'lat' => $hotel->getLatitude(),
|
||||
'lng' => $hotel->getLongitude(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$data = $this->configurationManager->getContentObject()->data;
|
||||
$this->view->assign('data', $data);
|
||||
$this->view->assign('markerData', json_encode($markerData, JSON_THROW_ON_ERROR | JSON_HEX_APOS));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $pageUid
|
||||
* @return string
|
||||
*/
|
||||
protected function getUriForPageUid($pageUid)
|
||||
{
|
||||
/** @var ContentObjectRenderer $contentObject */
|
||||
$contentObject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
|
||||
return $contentObject->typoLink_URL(
|
||||
[
|
||||
'parameter' => $pageUid,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Domain\Model\Dto\NewsletterSubscriptionRequest;
|
||||
use EP\EpProducts\MyEP\ApiClient;
|
||||
use EP\EpProducts\MyEP\ApiException;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
class NewsletterController extends ActionController
|
||||
{
|
||||
private ApiClient $apiClient;
|
||||
|
||||
public function __construct(ApiClient $apiClient)
|
||||
{
|
||||
$this->apiClient = $apiClient;
|
||||
}
|
||||
|
||||
public function indexAction()
|
||||
{
|
||||
$this->view->assign('result', GeneralUtility::_GET('result'));
|
||||
}
|
||||
|
||||
public function subscriptionFormAction(?NewsletterSubscriptionRequest $subscriptionRequest = null)
|
||||
{
|
||||
if (null === $subscriptionRequest) {
|
||||
$subscriptionRequest = new NewsletterSubscriptionRequest();
|
||||
}
|
||||
|
||||
try {
|
||||
$lists = $this->apiClient->getNewsletterLists();
|
||||
} catch (ApiException $e) {
|
||||
$lists = [];
|
||||
}
|
||||
|
||||
$this->view->assign('subscriptionRequest', $subscriptionRequest);
|
||||
$this->view->assign('lists', $lists);
|
||||
}
|
||||
|
||||
public function subscriptionFormSubmitAction(NewsletterSubscriptionRequest $subscriptionRequest)
|
||||
{
|
||||
try {
|
||||
$result = $this->apiClient->subscribeToNewsletters($subscriptionRequest);
|
||||
$result['success'] = true;
|
||||
} catch (ApiException $e) {
|
||||
$result = [
|
||||
'success' => false,
|
||||
'message' => $e->getMessage(),
|
||||
];
|
||||
}
|
||||
|
||||
$this->view->assign('result', $result);
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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 TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
class PricetableController extends ActionController
|
||||
{
|
||||
|
||||
public function eventAction()
|
||||
{
|
||||
$productUid = $this->settings['productUid'];
|
||||
$this->view->assign('productUid', $productUid);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Domain\Model\Region;
|
||||
use EP\EpProducts\Domain\Repository\RegionRepository;
|
||||
use EP\EpProducts\Service\ProductDataService;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
class RegionController extends ActionController
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \EP\EpProducts\Domain\Repository\RegionRepository
|
||||
*/
|
||||
protected $regionRepository;
|
||||
|
||||
/**
|
||||
* @var \EP\EpProducts\Service\ProductDataService
|
||||
*/
|
||||
protected $productDataService;
|
||||
|
||||
/**
|
||||
* @param RegionRepository $regionRepository
|
||||
* @param ProductDataService $productDataService
|
||||
*/
|
||||
public function __construct(RegionRepository $regionRepository, ProductDataService $productDataService)
|
||||
{
|
||||
$this->regionRepository = $regionRepository;
|
||||
$this->productDataService = $productDataService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Region $region
|
||||
*/
|
||||
public function detailAction(Region $region = null)
|
||||
{
|
||||
if ($region === null) {
|
||||
$regionUid = $this->settings['regionUid'];
|
||||
$region = $this->regionRepository->findByIdentifier($regionUid);
|
||||
}
|
||||
$additionalRegionUids = GeneralUtility::trimExplode(',', $this->settings['additionalRegionUids'], true);
|
||||
$additionalRegionUids = array_map(function ($uid) {
|
||||
return (int)$uid;
|
||||
}, $additionalRegionUids);
|
||||
$teaserRegionUids = array_merge([$region->getUid()], $additionalRegionUids);
|
||||
$filterSettings = [
|
||||
'regionUids' => $teaserRegionUids,
|
||||
];
|
||||
$excludedConceptUids = GeneralUtility::trimExplode(',', $this->settings['excludedConceptUids'], true);
|
||||
$limit = $this->settings['hideMoreLink'] ? 0 : 6;
|
||||
$teasers = $this->productDataService->getTeasergroup($filterSettings, $excludedConceptUids, $limit);
|
||||
$this->view->assign('teasers', $teasers);
|
||||
$this->view->assign('region', $region);
|
||||
$this->view->assign('filterSettings', $filterSettings);
|
||||
}
|
||||
|
||||
public function teasergroupAction()
|
||||
{
|
||||
$countryUid = (int)$this->settings['countryUid'];
|
||||
$season = $this->settings['season'];
|
||||
$regionsPid = (int)$this->settings['regionsStoragePid'];
|
||||
$regions = $this->regionRepository->getTeasersByCountryAndSeason($countryUid, $season, $regionsPid);
|
||||
$data = $this->configurationManager->getContentObject()->data;
|
||||
$this->view->assign('data', $data);
|
||||
$this->view->assign('teasers', $regions);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Domain\Model\Product;
|
||||
use EP\EpProducts\Domain\Model\Reseller;
|
||||
use EP\EpProducts\Service\MyEpUrlResolverService;
|
||||
use EP\EpProducts\Service\ResellerDataService;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
class ResellerController extends ActionController
|
||||
{
|
||||
/**
|
||||
* @var ResellerDataService
|
||||
*/
|
||||
protected $resellerDataService;
|
||||
|
||||
/**
|
||||
* @var MyEpUrlResolverService
|
||||
*/
|
||||
protected $myEpUrlResolverService;
|
||||
|
||||
/**
|
||||
* @param ResellerDataService $resellerDataService
|
||||
* @param MyEpUrlResolverService $myEpUrlResolverService
|
||||
*/
|
||||
public function __construct(
|
||||
ResellerDataService $resellerDataService,
|
||||
MyEpUrlResolverService $myEpUrlResolverService
|
||||
) {
|
||||
$this->resellerDataService = $resellerDataService;
|
||||
$this->myEpUrlResolverService = $myEpUrlResolverService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Reseller $reseller
|
||||
*/
|
||||
public function listAction(Reseller $reseller = null)
|
||||
{
|
||||
$products = [];
|
||||
|
||||
if ($reseller !== null) {
|
||||
$products = $reseller->getProducts();
|
||||
}
|
||||
|
||||
$this->view->assign('reseller', $reseller);
|
||||
$this->view->assign('products', $products);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Reseller $reseller
|
||||
* @param Product $product
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException
|
||||
*/
|
||||
public function copypasteAction(Reseller $reseller, Product $product)
|
||||
{
|
||||
if (!$reseller->getProducts()->contains($product)) {
|
||||
$this->redirect(
|
||||
'list',
|
||||
null,
|
||||
null,
|
||||
[ 'reseller' => $reseller ]
|
||||
);
|
||||
}
|
||||
|
||||
$myEpUrl = $this->myEpUrlResolverService->resolve();
|
||||
$productData = $this->resellerDataService->preprocessSingle($product, $reseller, $myEpUrl);
|
||||
|
||||
$this->view->assign('reseller', $reseller);
|
||||
$this->view->assign('productData', $productData);
|
||||
}
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Service\FilterService;
|
||||
use EP\EpProducts\Service\FilterSettingsEncoder;
|
||||
use EP\EpProducts\Service\SearchResultService;
|
||||
use EP\EpProducts\Traits\RequestArgumentTypeConversionTrait;
|
||||
use EP\EpProducts\Utility\DateUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
class SearchController extends ActionController
|
||||
{
|
||||
|
||||
use RequestArgumentTypeConversionTrait;
|
||||
|
||||
/**
|
||||
* @var \EP\EpProducts\Service\FilterService
|
||||
*/
|
||||
protected $filterService;
|
||||
|
||||
/**
|
||||
* @var SearchResultService
|
||||
*/
|
||||
private $searchResultService;
|
||||
|
||||
/**
|
||||
* @param FilterService $filterService
|
||||
*/
|
||||
public function __construct(FilterService $filterService, SearchResultService $searchResultService)
|
||||
{
|
||||
$this->filterService = $filterService;
|
||||
$this->searchResultService = $searchResultService;
|
||||
}
|
||||
|
||||
public function initializeProcessSearchAction()
|
||||
{
|
||||
$this->processSearchParamsArgument();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $searchParams
|
||||
*/
|
||||
public function processSearchAction(array $searchParams)
|
||||
{
|
||||
$filterSettings = $this->filterService->getFilterSettingsFromSearchParams($searchParams);
|
||||
|
||||
$redirectUri = $this->uriBuilder
|
||||
->reset()
|
||||
->setCreateAbsoluteUri(true)
|
||||
->uriFor(
|
||||
'searchresult',
|
||||
['filterSettings' => $filterSettings],
|
||||
null,
|
||||
null,
|
||||
'searchresult'
|
||||
);
|
||||
|
||||
$this->redirectToUri($redirectUri);
|
||||
}
|
||||
|
||||
public function initializeSearchresultAction()
|
||||
{
|
||||
// Process encoded filtersettings from static search result.
|
||||
// Explicit filter settings win: they carry the visitor's current selection,
|
||||
// whereas a stale 'f' riding along on a link would silently replace it.
|
||||
$encodedFilterSettings = GeneralUtility::_GET('f');
|
||||
if ($encodedFilterSettings && !$this->request->hasArgument('filterSettings')) {
|
||||
$filterSettingsEncoder = new FilterSettingsEncoder();
|
||||
$filterSettings = $filterSettingsEncoder->decode($encodedFilterSettings);
|
||||
if (count($filterSettings) > 0) {
|
||||
$this->request->setArgument('filterSettings', $filterSettings);
|
||||
}
|
||||
}
|
||||
$forcedConceptUids = GeneralUtility::intExplode(',', $this->settings['forcedConceptUids'], true);
|
||||
$this->processFilterSettingsArgument($forcedConceptUids);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $filterSettings
|
||||
*/
|
||||
public function searchresultAction(array $filterSettings)
|
||||
{
|
||||
$dateSelected = false;
|
||||
$organic = true;
|
||||
$forcedConceptUids = GeneralUtility::intExplode(',', $this->settings['forcedConceptUids'], true);
|
||||
$excludedConceptUids = GeneralUtility::intExplode(',', $this->settings['excludedConceptUids']);
|
||||
|
||||
if (!empty($filterSettings['dateFrom']) || !empty($filterSettings['dateTo'])) {
|
||||
$dateSelected = true;
|
||||
}
|
||||
|
||||
$searchResult = $this
|
||||
->searchResultService
|
||||
->getResult($filterSettings, $excludedConceptUids);
|
||||
|
||||
// No results? First retry without date constraint if any
|
||||
if ((!empty($filterSettings['dateFrom']) || !empty($filterSettings['dateTo'])) && 0 === $searchResult->getTotal()) {
|
||||
$filterSettings['dateFrom'] = null;
|
||||
$filterSettings['dateTo'] = null;
|
||||
$searchResult = $this->searchResultService->getResult($filterSettings, $excludedConceptUids);
|
||||
$organic = false;
|
||||
}
|
||||
|
||||
// Still no results? Remove all constraints and search again with defaults
|
||||
if (0 === $searchResult->getTotal()) {
|
||||
$filterSettings = $this->filterService->getNormalizedFilterSettings([], $forcedConceptUids);
|
||||
$searchResult = $this->searchResultService->getResult($filterSettings, $excludedConceptUids);
|
||||
$organic = false;
|
||||
}
|
||||
|
||||
$filterOptions = $this->filterService->collectFilterOptionsFromSearchResult($searchResult);
|
||||
|
||||
$referringPageUri = $this
|
||||
->uriBuilder
|
||||
->reset()
|
||||
->setTargetPageUid($this->settings['defaultSearchPageUid'])
|
||||
->setCreateAbsoluteUri(true)
|
||||
->uriFor(
|
||||
'searchresult',
|
||||
['filterSettings' => $filterSettings],
|
||||
'Search',
|
||||
'epproducts',
|
||||
'searchresult'
|
||||
)
|
||||
;
|
||||
|
||||
$this->view->assignMultiple([
|
||||
'filterSettings' => $filterSettings,
|
||||
'filterOptions' => $filterOptions,
|
||||
'searchResult' => $searchResult->getData(),
|
||||
'referringPageUri' => $referringPageUri,
|
||||
'stimulusController' => 'search',
|
||||
'meta' => [
|
||||
'organic' => $organic,
|
||||
'total' => $searchResult->getTotal(),
|
||||
'dateRange' => DateUtility::formatDateRange($filterSettings['dateFrom'], $filterSettings['dateTo']),
|
||||
'dateSelected' => $dateSelected,
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\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;
|
||||
|
||||
class SearchbarController extends ActionController
|
||||
{
|
||||
|
||||
use RequestArgumentTypeConversionTrait;
|
||||
|
||||
/**
|
||||
* @var FilterService
|
||||
*/
|
||||
protected $filterService;
|
||||
|
||||
/**
|
||||
* @var SearchResultService
|
||||
*/
|
||||
protected $searchResultService;
|
||||
|
||||
/**
|
||||
* @param FilterService $filterService
|
||||
* @param SearchResultService $searchResultService
|
||||
*/
|
||||
public function __construct(FilterService $filterService, SearchResultService $searchResultService)
|
||||
{
|
||||
$this->filterService = $filterService;
|
||||
$this->searchResultService = $searchResultService;
|
||||
}
|
||||
|
||||
public function initializeAction()
|
||||
{
|
||||
$this->processSearchParamsArgument();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $searchParams
|
||||
*/
|
||||
public function indexAction(array $searchParams)
|
||||
{
|
||||
$forcedConceptUids = GeneralUtility::trimExplode(',', $this->settings['forcedConceptUids'], true);
|
||||
$filterSettings = $this->filterService->getFilterSettingsFromSearchParams($searchParams, $forcedConceptUids);
|
||||
$excludedConceptUids = GeneralUtility::trimExplode(',', $this->settings['excludedConceptUids']);
|
||||
|
||||
$searchResult = $this
|
||||
->searchResultService
|
||||
->getResult($filterSettings, $excludedConceptUids);
|
||||
|
||||
$filterOptions = $this->filterService->collectFilterOptionsFromSearchResult($searchResult);
|
||||
|
||||
$this->view->assignMultiple([
|
||||
'filterOptions' => $filterOptions,
|
||||
'searchParams' => $searchParams,
|
||||
'collapsed' => (bool)$this->settings['collapsed'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Domain\Repository\SnowreportRepository;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
class SnowreportController extends ActionController
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \EP\EpProducts\Domain\Repository\SnowreportRepository
|
||||
*/
|
||||
protected $snowreportRepository;
|
||||
|
||||
/**
|
||||
* @param SnowreportRepository $snowreportRepository
|
||||
*/
|
||||
public function __construct(SnowreportRepository $snowreportRepository)
|
||||
{
|
||||
$this->snowreportRepository = $snowreportRepository;
|
||||
}
|
||||
|
||||
public function listAction()
|
||||
{
|
||||
$regionUids = GeneralUtility::trimExplode(',', $this->settings['regionUids'], true);
|
||||
$list = $this->snowreportRepository->getSnowreportsForRegions($regionUids);
|
||||
$data = $this->configurationManager->getContentObject()->data;
|
||||
$this->view->assign('data', $data);
|
||||
$this->view->assign('list', $list);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Domain\Model\Teammember;
|
||||
use EP\EpProducts\Domain\Repository\TeammemberRepository;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
class TeamController extends ActionController
|
||||
{
|
||||
/**
|
||||
* @var \EP\EpProducts\Domain\Repository\TeammemberRepository
|
||||
*/
|
||||
protected $teammemberRepository;
|
||||
|
||||
/**
|
||||
* @param TeammemberRepository $teammemberRepository
|
||||
*/
|
||||
public function __construct(TeammemberRepository $teammemberRepository)
|
||||
{
|
||||
$this->teammemberRepository = $teammemberRepository;
|
||||
}
|
||||
|
||||
public function listAction()
|
||||
{
|
||||
if (isset($this->settings['teamCategories']) && count(GeneralUtility::trimExplode(',', $this->settings['teamCategories'], true)) > 0) {
|
||||
$members = $this->teammemberRepository->findByCategories(GeneralUtility::trimExplode(',', $this->settings['teamCategories'], true));
|
||||
} else {
|
||||
$members = $this->teammemberRepository->findAll();
|
||||
}
|
||||
|
||||
$this->view->assign('members', $members);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Teammember $member
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException
|
||||
*/
|
||||
public function showAction(Teammember $member = null)
|
||||
{
|
||||
if ($member === null) {
|
||||
$this->redirect('list', null, null, null, null, 0, 302);
|
||||
}
|
||||
|
||||
$this->view->assign('member', $member);
|
||||
$this->view->assign('data', $this->configurationManager->getContentObject()->data);
|
||||
$this->view->assign('header', $this->coalesceHeader($member));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Teammember $member
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function coalesceHeader(Teammember $member)
|
||||
{
|
||||
$data = $this->configurationManager->getContentObject()->data;
|
||||
if (isset($data['header']) && $data['header'] !== '') {
|
||||
return $data['header'];
|
||||
}
|
||||
|
||||
$firstCategory = current($member->getCategories()->toArray());
|
||||
if ($firstCategory !== null && $firstCategory !== false) {
|
||||
return $firstCategory->getTitle();
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
use EP\EpProducts\Domain\Model\Travelinfo;
|
||||
use EP\EpProducts\Domain\Repository\TravelinfoRepository;
|
||||
use EP\EpProducts\MyEP\ApiClient;
|
||||
use EP\EpProducts\MyEP\ApiException;
|
||||
use TYPO3\CMS\Core\Http\ImmediateResponseException;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
use TYPO3\CMS\Frontend\Controller\ErrorController;
|
||||
|
||||
class TravelinfoController extends ActionController
|
||||
{
|
||||
private const SELECTION_ID_BOARD = 71;
|
||||
|
||||
/**
|
||||
* @var ApiClient
|
||||
*/
|
||||
private $apiClient;
|
||||
|
||||
/**
|
||||
* @var TravelinfoRepository
|
||||
*/
|
||||
private $travelinfoRepository;
|
||||
|
||||
public function __construct(ApiClient $apiClient, TravelinfoRepository $travelinfoRepository)
|
||||
{
|
||||
$this->apiClient = $apiClient;
|
||||
$this->travelinfoRepository = $travelinfoRepository;
|
||||
}
|
||||
|
||||
public function travelCodeAction(string $travelCode)
|
||||
{
|
||||
// find specific travel info by code including travel date first
|
||||
$travelInfo = $this->travelinfoRepository->findOneByTravelCode($travelCode);
|
||||
|
||||
// find general travel info by code without travel date as fallback
|
||||
if (null === $travelInfo) {
|
||||
$travelCodeBase = substr($travelCode, 0, -6);
|
||||
$travelInfo = $this->travelinfoRepository->findOneByTravelCode($travelCodeBase);
|
||||
}
|
||||
|
||||
// return 404 in case no travel info is available as last resort
|
||||
if (null === $travelInfo) {
|
||||
$response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
|
||||
$GLOBALS['TYPO3_REQUEST'],
|
||||
'Reiseinformationen nicht gefunden'
|
||||
);
|
||||
throw new ImmediateResponseException($response, 1731071856);
|
||||
}
|
||||
|
||||
$this->handleRequest($travelCode, $travelInfo);
|
||||
}
|
||||
|
||||
public function travelInfoAction(Travelinfo $travelInfo)
|
||||
{
|
||||
$travelCode = $travelInfo->getTravelCode();
|
||||
|
||||
$this->handleRequest($travelCode, $travelInfo);
|
||||
}
|
||||
|
||||
private function handleRequest(string $travelCode, Travelinfo $travelInfo)
|
||||
{
|
||||
|
||||
// fetch travel data via API call
|
||||
try {
|
||||
$travelData = $this->apiClient->getTravel($travelCode);
|
||||
} catch (ApiException $e) {
|
||||
$travelData = [];
|
||||
}
|
||||
|
||||
try {
|
||||
$pickupsPlanning = $this->apiClient->getPickupsPlanning($travelCode);
|
||||
} catch (ApiException $e) {
|
||||
$pickupsPlanning = [];
|
||||
}
|
||||
|
||||
// extract courses from additional services
|
||||
$courses = array_filter($travelData['additionalServices'] ?? [], function ($service) {
|
||||
return 'KUR' === $service['subType'];
|
||||
});
|
||||
|
||||
// extract board services from included services
|
||||
$includedServicesBoard = $travelData['selectionGroups'][self::SELECTION_ID_BOARD] ?? [];
|
||||
$board = $includedServicesBoard['selections'] ?? [];
|
||||
|
||||
// extract bus departure time if applicable
|
||||
$departureDayTime = null;
|
||||
$service = array_filter($travelData['transportationServices'] ?? [], function ($service) {
|
||||
return 'BUS' === $service['subType'] && 'RUECK' === $service['direction'];
|
||||
});
|
||||
if ($serviceDetail = reset($service)) {
|
||||
$departureDayTime = $serviceDetail['dayTime'];
|
||||
}
|
||||
|
||||
$this->view->assign('travelInfo', $travelInfo);
|
||||
$this->view->assign('travelData', $travelData);
|
||||
$this->view->assign('pickupsPlanning', $pickupsPlanning);
|
||||
$this->view->assign('courses', $courses);
|
||||
$this->view->assign('board', $board);
|
||||
$this->view->assign('departureDayTime', $departureDayTime);
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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 TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
class WatchlistController extends ActionController
|
||||
{
|
||||
|
||||
public function listAction()
|
||||
{
|
||||
$data = $this->configurationManager->getContentObject()->data;
|
||||
$this->view->assign('data', $data);
|
||||
$this->view->assign('referringPageUid', $GLOBALS['TSFE']->id);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\CsvFormatter;
|
||||
|
||||
class FacebookCatalogCsvFormatter
|
||||
{
|
||||
/**
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public static function format(array $data)
|
||||
{
|
||||
$csv = [];
|
||||
|
||||
$csv[] = [
|
||||
'id',
|
||||
'availability',
|
||||
'condition',
|
||||
'description',
|
||||
'image_link',
|
||||
'link',
|
||||
'title',
|
||||
'price',
|
||||
'brand',
|
||||
];
|
||||
|
||||
foreach ($data['product'] as $product) {
|
||||
if (!isset($product['hotels']['hotel'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$minPrice = 0;
|
||||
$available = 0;
|
||||
|
||||
foreach ($product['hotels']['hotel'] as $hotel) {
|
||||
if (!isset($hotel['dates']['date'])) {
|
||||
continue;
|
||||
}
|
||||
foreach ($hotel['dates']['date'] as $date) {
|
||||
if ($minPrice === 0 || $date['minprice'] < $minPrice) {
|
||||
$minPrice = $date['minprice'];
|
||||
}
|
||||
$available++;
|
||||
}
|
||||
}
|
||||
|
||||
$description = preg_replace( "/\r|\n/", ' ', $product['description']);
|
||||
$description = strip_tags($description);
|
||||
$description = htmlspecialchars_decode($description);
|
||||
|
||||
$csv[] = [
|
||||
$product['@id'],
|
||||
$available > 0 ? 'in stock' : 'out of stock',
|
||||
'new',
|
||||
$description,
|
||||
$product['images']['image'][0],
|
||||
$product['link'],
|
||||
$product['name'],
|
||||
sprintf('%.2f EUR', $minPrice),
|
||||
'brand-epreisen'
|
||||
];
|
||||
}
|
||||
|
||||
return $csv;
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\CsvFormatter;
|
||||
|
||||
class GoogleBusinessFeedCsvFormatter
|
||||
{
|
||||
/**
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public static function format(array $data)
|
||||
{
|
||||
$csv = [];
|
||||
|
||||
$csv[] = [
|
||||
'Destination ID',
|
||||
'Origin ID',
|
||||
'Title',
|
||||
'Final URL',
|
||||
'Image URL',
|
||||
'Price',
|
||||
];
|
||||
|
||||
foreach ($data['product'] as $product) {
|
||||
if (!isset($product['hotels']['hotel'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$minPrice = 0;
|
||||
$available = 0;
|
||||
|
||||
foreach ($product['hotels']['hotel'] as $hotel) {
|
||||
if (!isset($hotel['dates']['date'])) {
|
||||
continue;
|
||||
}
|
||||
foreach ($hotel['dates']['date'] as $date) {
|
||||
if ($minPrice === 0 || $date['minprice'] < $minPrice) {
|
||||
$minPrice = $date['minprice'];
|
||||
}
|
||||
$available++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($available > 0) {
|
||||
$csv[] = [
|
||||
$product['@id'],
|
||||
$product['@id'],
|
||||
$product['name'],
|
||||
$product['link'],
|
||||
$product['images']['image'][0],
|
||||
sprintf('%.2f EUR', $minPrice),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $csv;
|
||||
}
|
||||
}
|
||||
@@ -1,484 +0,0 @@
|
||||
<?php
|
||||
namespace EP\EpProducts\Domain\Model\Dto;
|
||||
|
||||
use EP\EpProducts\Domain\Model\GroupsPriceBoard;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2020 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!
|
||||
***************************************************************/
|
||||
|
||||
class GroupsPriceInquiry
|
||||
{
|
||||
const MODE_INQUIRY = 'inquiry';
|
||||
const MODE_BOOKING = 'booking';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $mode;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
* @TYPO3\CMS\Extbase\Annotation\Validate("Boolean", options={"is": true})
|
||||
*/
|
||||
protected $confirmation;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
|
||||
*/
|
||||
protected $group;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
|
||||
*/
|
||||
protected $street;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
|
||||
*/
|
||||
protected $postcode;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
|
||||
*/
|
||||
protected $city;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
|
||||
* @TYPO3\CMS\Extbase\Annotation\Validate("EmailAddress")
|
||||
*/
|
||||
protected $email;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
|
||||
*/
|
||||
protected $phone;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $remarks;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
|
||||
*/
|
||||
protected $dateFrom;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
|
||||
*/
|
||||
protected $dateTo;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $nights;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $pax;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $children;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $minors;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $adolescents;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $options = [];
|
||||
|
||||
/**
|
||||
* @var GroupsPriceBoard
|
||||
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
|
||||
*/
|
||||
protected $board;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $summary;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->mode = self::MODE_BOOKING;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isConfirmation()
|
||||
{
|
||||
return $this->confirmation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $confirmation
|
||||
*/
|
||||
public function setConfirmation($confirmation)
|
||||
{
|
||||
$this->confirmation = $confirmation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getMode()
|
||||
{
|
||||
return $this->mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mode
|
||||
*/
|
||||
public function setMode($mode)
|
||||
{
|
||||
$this->mode = $mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getGroup()
|
||||
{
|
||||
return $this->group;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $group
|
||||
*/
|
||||
public function setGroup($group)
|
||||
{
|
||||
$this->group = $group;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getStreet()
|
||||
{
|
||||
return $this->street;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $street
|
||||
*/
|
||||
public function setStreet($street)
|
||||
{
|
||||
$this->street = $street;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPostcode()
|
||||
{
|
||||
return $this->postcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $postcode
|
||||
*/
|
||||
public function setPostcode($postcode)
|
||||
{
|
||||
$this->postcode = $postcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCity()
|
||||
{
|
||||
return $this->city;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $city
|
||||
*/
|
||||
public function setCity($city)
|
||||
{
|
||||
$this->city = $city;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEmail()
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $email
|
||||
*/
|
||||
public function setEmail($email)
|
||||
{
|
||||
$this->email = $email;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPhone()
|
||||
{
|
||||
return $this->phone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $phone
|
||||
*/
|
||||
public function setPhone($phone)
|
||||
{
|
||||
$this->phone = $phone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRemarks()
|
||||
{
|
||||
return $this->remarks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $remarks
|
||||
*/
|
||||
public function setRemarks($remarks)
|
||||
{
|
||||
$this->remarks = $remarks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDateFrom()
|
||||
{
|
||||
return $this->dateFrom;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $dateFrom
|
||||
*/
|
||||
public function setDateFrom($dateFrom)
|
||||
{
|
||||
$this->dateFrom = $dateFrom;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDateTo()
|
||||
{
|
||||
return $this->dateTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $dateTo
|
||||
*/
|
||||
public function setDateTo($dateTo)
|
||||
{
|
||||
$this->dateTo = $dateTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getNights()
|
||||
{
|
||||
return $this->nights;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $nights
|
||||
*/
|
||||
public function setNights($nights)
|
||||
{
|
||||
$this->nights = $nights;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPax()
|
||||
{
|
||||
return $this->pax;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $pax
|
||||
*/
|
||||
public function setPax($pax)
|
||||
{
|
||||
$this->pax = $pax;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getChildren()
|
||||
{
|
||||
return $this->children;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $pax
|
||||
*/
|
||||
public function setChildren($children)
|
||||
{
|
||||
$this->children = $children;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getMinors()
|
||||
{
|
||||
return $this->minors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $minors
|
||||
*/
|
||||
public function setMinors($minors)
|
||||
{
|
||||
$this->minors = $minors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getAdolescents()
|
||||
{
|
||||
return $this->adolescents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $adolescents
|
||||
*/
|
||||
public function setAdolescents($adolescents)
|
||||
{
|
||||
$this->adolescents = $adolescents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getEffectivePax()
|
||||
{
|
||||
return max(30, (int) $this->getPax() - (int) $this->getChildren());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
*/
|
||||
public function setOptions(array $options = [])
|
||||
{
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return GroupsPriceBoard
|
||||
*/
|
||||
public function getBoard()
|
||||
{
|
||||
return $this->board;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GroupsPriceBoard $board
|
||||
*/
|
||||
public function setBoard(GroupsPriceBoard $board = null)
|
||||
{
|
||||
$this->board = $board;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getSummary()
|
||||
{
|
||||
return $this->summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $summary
|
||||
*/
|
||||
public function setSummary(array $summary)
|
||||
{
|
||||
$this->summary = $summary;
|
||||
}
|
||||
}
|
||||
@@ -1,329 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Domain\Model;
|
||||
|
||||
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
|
||||
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
|
||||
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
|
||||
|
||||
class Travelinfo extends AbstractEntity
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $title;
|
||||
|
||||
/**
|
||||
* @var FileReference
|
||||
*/
|
||||
protected $headerImage;
|
||||
|
||||
/**
|
||||
* @var FileReference
|
||||
*/
|
||||
protected $footerImage;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $subline;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $headline;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $introText;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $busInfoText;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $departureText;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $footerText;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $additionalInfo;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $importantPhoneNumbers;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $importantLinks;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $selfArrangedText;
|
||||
|
||||
/**
|
||||
* @var ObjectStorage<TravelinfoTeaser>
|
||||
*/
|
||||
protected $teasers;
|
||||
|
||||
/**
|
||||
* @var ObjectStorage<TravelinfoLink>
|
||||
*/
|
||||
protected $links;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $travelCode;
|
||||
|
||||
/**
|
||||
* @var Product
|
||||
*/
|
||||
protected $product;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $hideAddress = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->initStorageObjects();
|
||||
}
|
||||
|
||||
protected function initStorageObjects()
|
||||
{
|
||||
$this->teasers = new ObjectStorage();
|
||||
$this->links = new ObjectStorage();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle()
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $title
|
||||
*/
|
||||
public function setTitle($title)
|
||||
{
|
||||
$this->title = $title;
|
||||
}
|
||||
|
||||
public function getHeaderImage()
|
||||
{
|
||||
return $this->headerImage;
|
||||
}
|
||||
|
||||
public function setHeaderImage($headerImage)
|
||||
{
|
||||
$this->headerImage = $headerImage;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFooterImage()
|
||||
{
|
||||
return $this->footerImage;
|
||||
}
|
||||
|
||||
public function setFooterImage($footerImage)
|
||||
{
|
||||
$this->footerImage = $footerImage;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSubline()
|
||||
{
|
||||
return $this->subline;
|
||||
}
|
||||
|
||||
public function setSubline($subline)
|
||||
{
|
||||
$this->subline = $subline;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHeadline()
|
||||
{
|
||||
return $this->headline;
|
||||
}
|
||||
|
||||
public function setHeadline($headline)
|
||||
{
|
||||
$this->headline = $headline;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIntroText()
|
||||
{
|
||||
return $this->introText;
|
||||
}
|
||||
|
||||
public function setIntroText($introText)
|
||||
{
|
||||
$this->introText = $introText;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBusInfoText()
|
||||
{
|
||||
return $this->busInfoText;
|
||||
}
|
||||
|
||||
public function setBusInfoText($busInfoText)
|
||||
{
|
||||
$this->busInfoText = $busInfoText;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDepartureText()
|
||||
{
|
||||
return $this->departureText;
|
||||
}
|
||||
|
||||
public function setDepartureText($departureText)
|
||||
{
|
||||
$this->departureText = $departureText;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFooterText()
|
||||
{
|
||||
return $this->footerText;
|
||||
}
|
||||
|
||||
public function setFooterText($footerText)
|
||||
{
|
||||
$this->footerText = $footerText;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAdditionalInfo()
|
||||
{
|
||||
return $this->additionalInfo;
|
||||
}
|
||||
|
||||
public function setAdditionalInfo($additionalInfo)
|
||||
{
|
||||
$this->additionalInfo = $additionalInfo;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getImportantPhoneNumbers()
|
||||
{
|
||||
return $this->importantPhoneNumbers;
|
||||
}
|
||||
|
||||
public function setImportantPhoneNumbers($importantPhoneNumbers)
|
||||
{
|
||||
$this->importantPhoneNumbers = $importantPhoneNumbers;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getImportantLinks()
|
||||
{
|
||||
return $this->importantLinks;
|
||||
}
|
||||
|
||||
public function setImportantLinks($importantLinks)
|
||||
{
|
||||
$this->importantLinks = $importantLinks;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSelfArrangedText()
|
||||
{
|
||||
return $this->selfArrangedText;
|
||||
}
|
||||
|
||||
public function setSelfArrangedText($selfArrangedText)
|
||||
{
|
||||
$this->selfArrangedText = $selfArrangedText;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTeasers()
|
||||
{
|
||||
return $this->teasers;
|
||||
}
|
||||
|
||||
public function setTeasers($teasers)
|
||||
{
|
||||
$this->teasers = $teasers;
|
||||
}
|
||||
|
||||
public function getLinks()
|
||||
{
|
||||
return $this->links;
|
||||
}
|
||||
|
||||
public function setLinks($links)
|
||||
{
|
||||
$this->links = $links;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTravelCode()
|
||||
{
|
||||
return $this->travelCode;
|
||||
}
|
||||
|
||||
public function setTravelCode($travelCode)
|
||||
{
|
||||
$this->travelCode = $travelCode;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getProduct()
|
||||
{
|
||||
return $this->product;
|
||||
}
|
||||
|
||||
public function setProduct($product)
|
||||
{
|
||||
$this->product = $product;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isHideAddress()
|
||||
{
|
||||
return $this->hideAddress;
|
||||
}
|
||||
|
||||
public function setHideAddress($hideAddress)
|
||||
{
|
||||
$this->hideAddress = $hideAddress;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Domain\Model;
|
||||
|
||||
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
|
||||
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
|
||||
|
||||
class TravelinfoLink extends AbstractEntity
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $title;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $link;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $icon;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle()
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $title
|
||||
*/
|
||||
public function setTitle($title)
|
||||
{
|
||||
$this->title = $title;
|
||||
}
|
||||
|
||||
public function getLink()
|
||||
{
|
||||
return $this->link;
|
||||
}
|
||||
|
||||
public function setLink($link)
|
||||
{
|
||||
$this->link = $link;
|
||||
}
|
||||
|
||||
public function getIcon()
|
||||
{
|
||||
return $this->icon;
|
||||
}
|
||||
|
||||
public function setIcon($icon)
|
||||
{
|
||||
$this->icon = $icon;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Domain\Model;
|
||||
|
||||
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
|
||||
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
|
||||
|
||||
class TravelinfoTeaser extends AbstractEntity
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $title;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $bodytext;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $category;
|
||||
|
||||
/**
|
||||
* @var FileReference
|
||||
*/
|
||||
protected $image;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle()
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $title
|
||||
*/
|
||||
public function setTitle($title)
|
||||
{
|
||||
$this->title = $title;
|
||||
}
|
||||
|
||||
public function getBodytext()
|
||||
{
|
||||
return $this->bodytext;
|
||||
}
|
||||
|
||||
public function setBodytext($bodytext)
|
||||
{
|
||||
$this->bodytext = $bodytext;
|
||||
}
|
||||
|
||||
public function getCategory()
|
||||
{
|
||||
return $this->category;
|
||||
}
|
||||
|
||||
public function setCategory($category)
|
||||
{
|
||||
$this->category = $category;
|
||||
}
|
||||
|
||||
public function getImage()
|
||||
{
|
||||
return $this->image;
|
||||
}
|
||||
|
||||
public function setImage($image)
|
||||
{
|
||||
$this->image = $image;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Domain\Repository;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Domain\Model\Faq;
|
||||
use TYPO3\CMS\Core\Database\Connection;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper;
|
||||
|
||||
class FaqRepository extends AbstractRepository
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $uids
|
||||
* @return array
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
public function findByUids($uids)
|
||||
{
|
||||
/** @var DataMapper $dataMapper */
|
||||
$dataMapper = $this->objectManager->get(DataMapper::class);
|
||||
$qb = $this->getDbConnection()->createQueryBuilder();
|
||||
|
||||
$rows = $qb
|
||||
->select('*')
|
||||
->from('tx_epproducts_domain_model_faq')
|
||||
->where('uid IN (:uids)')
|
||||
->add('orderBy', 'FIELD(uid, ' . $uids . ')')
|
||||
->setParameter('uids', GeneralUtility::trimExplode(',', $uids), Connection::PARAM_INT_ARRAY)
|
||||
->execute()
|
||||
->fetchAllAssociative()
|
||||
;
|
||||
|
||||
return $dataMapper->map(Faq::class, $rows);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Domain\Repository;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2020 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 TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings;
|
||||
use TYPO3\CMS\Extbase\Persistence\Repository;
|
||||
|
||||
class GroupsPriceOptionRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* @param array $uids
|
||||
* @return array
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
|
||||
*/
|
||||
public function findByUids(array $uids)
|
||||
{
|
||||
if (0 === count($uids)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
/** @var Typo3QuerySettings $querySettings */
|
||||
$querySettings = $this->objectManager->get(Typo3QuerySettings::class);
|
||||
$querySettings->setRespectStoragePage(false);
|
||||
$this->setDefaultQuerySettings($querySettings);
|
||||
|
||||
$query = $this->createQuery();
|
||||
$query->matching($query->in('uid', $uids));
|
||||
|
||||
return $query->execute()->toArray();
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Domain\Repository;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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!
|
||||
***************************************************************/
|
||||
|
||||
class MatchCodeRepository extends AbstractRepository
|
||||
{}
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Domain\Repository;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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!
|
||||
***************************************************************/
|
||||
|
||||
class ResellerRepository extends AbstractRepository
|
||||
{}
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Domain\Repository;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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!
|
||||
***************************************************************/
|
||||
|
||||
class RoomRepository extends AbstractRepository
|
||||
{}
|
||||
@@ -1,71 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Domain\Repository;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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 TYPO3\CMS\Core\Database\Connection;
|
||||
|
||||
class SnowreportRepository extends AbstractRepository
|
||||
{
|
||||
|
||||
/**
|
||||
* @param array $regionUids
|
||||
* @return array
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
public function getSnowreportsForRegions(array $regionUids = null)
|
||||
{
|
||||
$qb = $this->getDbConnection()->createQueryBuilder();
|
||||
|
||||
$query = $qb
|
||||
->select(
|
||||
'snowreport.*',
|
||||
'region.name as regionName', 'region.uid as regionUid', 'region.detail_page as regionDetailPage',
|
||||
'country.name as countryName', 'country.uid as countryUid', 'country.code as countryCode',
|
||||
'country.detail_page as countryDetailPage',
|
||||
'season_start as seasonStart', 'season_end as seasonEnd'
|
||||
)
|
||||
->addSelectLiteral('(UNIX_TIMESTAMP() >= snowreport.season_start AND UNIX_TIMESTAMP() <= snowreport.season_end) as inSeason')
|
||||
->from('tx_epproducts_domain_model_snowreport', 'snowreport')
|
||||
->innerJoin('snowreport', 'tx_epproducts_domain_model_region', 'region', 'snowreport.uid = region.snowreport')
|
||||
->innerJoin('region', 'tx_epproducts_domain_model_country', 'country', 'region.country = country.uid')
|
||||
->where('region.snowreport > 0')
|
||||
->groupBy('snowreport.vendor_uid')
|
||||
->orderBy('region.name')
|
||||
;
|
||||
|
||||
if ($regionUids) {
|
||||
$qb
|
||||
->andWhere('region.uid IN (:regionUids)')
|
||||
->setParameter('regionUids', $regionUids, Connection::PARAM_INT_ARRAY)
|
||||
;
|
||||
}
|
||||
|
||||
return $query->execute()->fetchAllAssociative();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Domain\Repository;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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!
|
||||
***************************************************************/
|
||||
|
||||
class TeammemberRepository extends AbstractRepository
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $defaultOrderings = [
|
||||
'sorting' => 'ASC',
|
||||
];
|
||||
|
||||
/**
|
||||
* @param array $categories
|
||||
* @return array|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
|
||||
*/
|
||||
public function findByCategories(array $categories = [])
|
||||
{
|
||||
$qb = $this->createQuery();
|
||||
|
||||
$qb->matching($qb->in('categories.uid', $categories));
|
||||
|
||||
return $qb->execute();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Domain\Repository;
|
||||
|
||||
class TravelinfoRepository extends AbstractRepository
|
||||
{}
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Domain\Repository;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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!
|
||||
***************************************************************/
|
||||
|
||||
class WebcamRepository extends AbstractRepository
|
||||
{}
|
||||
@@ -1,244 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\EpTeam;
|
||||
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Psr\Log\LoggerAwareTrait;
|
||||
use Symfony\Component\HttpClient\HttpClient;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* The MyE&P Team application (Symfony). Separate from EP\EpProducts\MyEP\ApiClient on purpose:
|
||||
* this is a different application on its own host, authenticated with a shared key in a header
|
||||
* instead of the OAuth client-credentials flow MyE&P uses, so it shares neither the base URI nor
|
||||
* the token handling.
|
||||
*/
|
||||
class ApiClient implements LoggerAwareInterface
|
||||
{
|
||||
use LoggerAwareTrait;
|
||||
|
||||
/**
|
||||
* Applied when extension configuration does not override them. Seconds.
|
||||
*/
|
||||
private const DEFAULT_TIMEOUT = 5;
|
||||
private const DEFAULT_MAX_DURATION = 15;
|
||||
|
||||
/**
|
||||
* Status codes the endpoint answers a stored submission with. A conflict is included for the
|
||||
* dedupe the team application may add later - it is not returned today - because a
|
||||
* double-clicked submit button is not something to report.
|
||||
*/
|
||||
private const ACCEPTED_STATUS_CODES = [
|
||||
Response::HTTP_OK,
|
||||
Response::HTTP_CREATED,
|
||||
Response::HTTP_ACCEPTED,
|
||||
Response::HTTP_NO_CONTENT,
|
||||
Response::HTTP_CONFLICT,
|
||||
];
|
||||
|
||||
/**
|
||||
* How much of a rejected response is carried into the exception message. A 400 names the
|
||||
* offending field in its body, which is the only way to tell from a log why a submission
|
||||
* was refused.
|
||||
*/
|
||||
private const ERROR_BODY_EXCERPT_LENGTH = 500;
|
||||
|
||||
/**
|
||||
* Shared, like the MyE&P client: Symfony's CurlHttpClient keeps its connection pool and TLS
|
||||
* session cache per instance. The API key is a constant, so unlike a bearer token it can be
|
||||
* a client default header and the instance can live as long as the request.
|
||||
*/
|
||||
private static ?HttpClientInterface $httpClient = null;
|
||||
|
||||
private ?array $configuration = null;
|
||||
|
||||
/**
|
||||
* Posts a submitted TYPO3 form to POST /api/application-forms.
|
||||
*
|
||||
* @throws ApiException
|
||||
*/
|
||||
public function submitApplicationForm(array $payload): void
|
||||
{
|
||||
$uri = 'api/application-forms';
|
||||
|
||||
// 'json' also sets the Content-Type the endpoint requires - without it the body is not
|
||||
// read as JSON and the answer is a 400.
|
||||
$response = $this->request('POST', $uri, [
|
||||
'json' => $payload,
|
||||
]);
|
||||
|
||||
$statusCode = $this->readStatusCode($response, 'POST', $uri);
|
||||
|
||||
if (false === in_array($statusCode, self::ACCEPTED_STATUS_CODES, true)) {
|
||||
$message = sprintf(
|
||||
'EP Team API returned unexpected status %d for POST %s: %s',
|
||||
$statusCode,
|
||||
$uri,
|
||||
$this->readErrorBody($response)
|
||||
);
|
||||
$this->logWarning($message);
|
||||
|
||||
throw new ApiException($message, $statusCode);
|
||||
}
|
||||
|
||||
$this->logAcceptedSubmission($response, $payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiException
|
||||
*/
|
||||
private function request(string $method, string $uri, array $options): ResponseInterface
|
||||
{
|
||||
try {
|
||||
return $this->getHttpClient()->request($method, $uri, $options);
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$message = sprintf('EP Team API transport error for %s %s: %s', $method, $uri, $e->getMessage());
|
||||
$this->logError($message, ['exception' => $e]);
|
||||
|
||||
throw new ApiException($message, 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reading the status completes the transfer, so this is also what turns the lazy response
|
||||
* returned by the client into a finished request.
|
||||
*
|
||||
* @throws ApiException
|
||||
*/
|
||||
private function readStatusCode(ResponseInterface $response, string $method, string $uri): int
|
||||
{
|
||||
try {
|
||||
return $response->getStatusCode();
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$message = sprintf('EP Team API transport error while reading status for %s %s: %s', $method, $uri, $e->getMessage());
|
||||
$this->logError($message, ['exception' => $e]);
|
||||
|
||||
throw new ApiException($message, 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
private function readErrorBody(ResponseInterface $response): string
|
||||
{
|
||||
try {
|
||||
$body = trim($response->getContent(false));
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
return '<no response body>';
|
||||
}
|
||||
|
||||
if ('' === $body) {
|
||||
return '<empty response body>';
|
||||
}
|
||||
|
||||
if (mb_strlen($body) > self::ERROR_BODY_EXCERPT_LENGTH) {
|
||||
$body = mb_substr($body, 0, self::ERROR_BODY_EXCERPT_LENGTH) . '…';
|
||||
}
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* The submission uuid the endpoint returns is what makes a support question ("did our
|
||||
* application arrive?") answerable from the TYPO3 log alone. Reading the body also drains
|
||||
* the response, which returns the connection to the pool instead of cancelling the transfer.
|
||||
* Deliberately without any of the submitted values: these payloads are personal data.
|
||||
*/
|
||||
private function logAcceptedSubmission(ResponseInterface $response, array $payload): void
|
||||
{
|
||||
try {
|
||||
$data = $response->toArray(false);
|
||||
} catch (\Throwable $e) {
|
||||
// A body that is absent (204) or not JSON costs nothing here - the submission is
|
||||
// stored either way, which the asserted status has already established.
|
||||
return;
|
||||
}
|
||||
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->info('Application form submission accepted by the EP Team API.', [
|
||||
'form' => $payload['form'] ?? null,
|
||||
'pageUid' => $payload['pageUid'] ?? null,
|
||||
'uuid' => $data['uuid'] ?? null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiException
|
||||
*/
|
||||
private function getHttpClient(): HttpClientInterface
|
||||
{
|
||||
if (null !== static::$httpClient) {
|
||||
return static::$httpClient;
|
||||
}
|
||||
|
||||
$config = $this->getConfiguration();
|
||||
$baseUrl = trim((string)($config['epTeamApiBaseUrl'] ?? ''));
|
||||
$apiKey = trim((string)($config['epTeamApiKey'] ?? ''));
|
||||
|
||||
if ('' === $baseUrl) {
|
||||
throw new ApiException('EP Team API base URL is not configured.');
|
||||
}
|
||||
if ('' === $apiKey) {
|
||||
throw new ApiException('EP Team API key is not configured.');
|
||||
}
|
||||
if (0 !== strpos($baseUrl, 'https://')) {
|
||||
// The application answers an http request with a 301 to the https URL, and this
|
||||
// client does not follow redirects, so a plain http base URL fails every submission.
|
||||
$this->logWarning(sprintf('EP Team API base URL is not https (%s); submissions will fail on the redirect.', $baseUrl));
|
||||
}
|
||||
|
||||
$options = [
|
||||
'headers' => [
|
||||
'X-Api-Key' => $apiKey,
|
||||
],
|
||||
];
|
||||
|
||||
// Without these the client falls back to PHP's default_socket_timeout (commonly 60s),
|
||||
// so a stalled API pins a PHP worker for a minute per request - and this call happens
|
||||
// inside the visitor's form submission, with the visitor waiting for it. The defaults
|
||||
// live in code rather than in ext_conf_template.txt: ExtensionConfiguration::get()
|
||||
// returns the stored configuration verbatim and only syncs the template when an
|
||||
// extension has no configuration at all, so a newly added template key is absent until
|
||||
// someone saves extension configuration by hand. Falling back to 0 there would silently
|
||||
// mean "no timeout" - the opposite of what this guard is for. An explicit 0 still
|
||||
// disables.
|
||||
$timeout = (int)($config['epTeamApiTimeout'] ?? self::DEFAULT_TIMEOUT);
|
||||
if ($timeout > 0) {
|
||||
$options['timeout'] = $timeout;
|
||||
}
|
||||
$maxDuration = (int)($config['epTeamApiMaxDuration'] ?? self::DEFAULT_MAX_DURATION);
|
||||
if ($maxDuration > 0) {
|
||||
$options['max_duration'] = $maxDuration;
|
||||
}
|
||||
|
||||
return static::$httpClient = HttpClient::createForBaseUri(rtrim($baseUrl, '/') . '/', $options);
|
||||
}
|
||||
|
||||
private function getConfiguration(): array
|
||||
{
|
||||
if (null === $this->configuration) {
|
||||
$this->configuration = GeneralUtility::makeInstance(ExtensionConfiguration::class)
|
||||
->get('ep_products');
|
||||
}
|
||||
|
||||
return $this->configuration;
|
||||
}
|
||||
|
||||
private function logError(string $message, array $context = []): void
|
||||
{
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->error($message, $context);
|
||||
}
|
||||
}
|
||||
|
||||
private function logWarning(string $message, array $context = []): void
|
||||
{
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->warning($message, $context);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\EpTeam;
|
||||
|
||||
class ApiException extends \RuntimeException
|
||||
{
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\EventListener;
|
||||
|
||||
use EP\EpProducts\Service\ImportTimestampService;
|
||||
use TYPO3\CMS\Backend\Backend\Event\SystemInformationToolbarCollectorEvent;
|
||||
|
||||
class SystemInformationToolbarListener
|
||||
{
|
||||
public function __invoke(SystemInformationToolbarCollectorEvent $event): void
|
||||
{
|
||||
$timestampService = new ImportTimestampService();
|
||||
$productDataUpdatedTimestamp = $timestampService->readImportTimestamp('fileadmin/products_import.info');
|
||||
$contingentsDataUpdatedTimestamp = $timestampService->readImportTimestamp('fileadmin/contingents_import.info');
|
||||
|
||||
$event->getToolbarItem()->addSystemInformation(
|
||||
'Letzer Produktdaten-Import',
|
||||
$productDataUpdatedTimestamp ? $productDataUpdatedTimestamp->format('d.m.y H:i:s') : '-',
|
||||
'ep-logo'
|
||||
);
|
||||
$event->getToolbarItem()->addSystemInformation(
|
||||
'Letzer Kontingente Import',
|
||||
$contingentsDataUpdatedTimestamp ? $contingentsDataUpdatedTimestamp->format('d.m.y H:i:s') : '-',
|
||||
'ep-logo'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,258 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Hooks;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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 TYPO3\CMS\Backend\Utility\BackendUtility;
|
||||
use TYPO3\CMS\Backend\View\PageLayoutView as CorePageLayoutView;
|
||||
use TYPO3\CMS\Backend\View\PageLayoutViewDrawItemHookInterface;
|
||||
use TYPO3\CMS\Core\Service\FlexFormService;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
class PageLayoutView implements PageLayoutViewDrawItemHookInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param CorePageLayoutView $parentObject
|
||||
* @param bool $drawItem
|
||||
* @param string $headerContent
|
||||
* @param string $itemContent
|
||||
* @param array $row
|
||||
*/
|
||||
public function preProcess(CorePageLayoutView &$parentObject, &$drawItem, &$headerContent, &$itemContent, array &$row) {
|
||||
// Country detail
|
||||
if ($row['CType'] === 'list' && $row['list_type'] === 'epproducts_country_detail') {
|
||||
$flexFormData = $this->getFlexFormData($row);
|
||||
$drawItem = false;
|
||||
$countryUid = $flexFormData['settings']['countryUid'];
|
||||
$name = $this->getName('country', $countryUid);
|
||||
$itemContent = '<strong>Detailseite Land</strong><br />' . $name;
|
||||
}
|
||||
|
||||
// Region teaser
|
||||
if ($row['CType'] === 'list' && $row['list_type'] === 'epproducts_region_teasergroup') {
|
||||
$flexFormData = $this->getFlexFormData($row);
|
||||
$drawItem = false;
|
||||
$countryUid = $flexFormData['settings']['countryUid'];
|
||||
$name = $this->getName('country', $countryUid);
|
||||
$itemContent = '<strong>Teasergruppe Gebiete</strong><br />' . $name;
|
||||
}
|
||||
|
||||
// Region detail
|
||||
if ($row['CType'] === 'list' && $row['list_type'] === 'epproducts_region_detail') {
|
||||
$flexFormData = $this->getFlexFormData($row);
|
||||
$drawItem = false;
|
||||
$regionUid = $flexFormData['settings']['regionUid'];
|
||||
$name = $this->getName('region', $regionUid);
|
||||
$itemContent = '<strong>Detailseite Gebiet</strong><br />' . $name;
|
||||
}
|
||||
|
||||
// City teaser
|
||||
if ($row['CType'] === 'list' && $row['list_type'] === 'epproducts_city_teasergroup') {
|
||||
$flexFormData = $this->getFlexFormData($row);
|
||||
$drawItem = false;
|
||||
$countryUid = $flexFormData['settings']['countryUid'];
|
||||
$regionUid = $flexFormData['settings']['regionUid'];
|
||||
$record = [];
|
||||
if ((int) $regionUid > 0) {
|
||||
$name = $this->getName('region', $regionUid);
|
||||
} elseif ((int) $countryUid > 0) {
|
||||
$name = $this->getName('country', $countryUid);
|
||||
}
|
||||
$itemContent = '<strong>Teasergruppe Orte</strong><br />';
|
||||
if (count($record) > 0) {
|
||||
$itemContent .= $name;
|
||||
}
|
||||
}
|
||||
|
||||
// City detail
|
||||
if ($row['CType'] === 'list' && $row['list_type'] === 'epproducts_city_detail') {
|
||||
$flexFormData = $this->getFlexFormData($row);
|
||||
$drawItem = false;
|
||||
$cityUid = $flexFormData['settings']['cityUid'];
|
||||
$name = $this->getName('city', $cityUid);
|
||||
$itemContent = '<strong>Detailseite Ort</strong><br />' . $name;
|
||||
}
|
||||
|
||||
// Hotel Teaser
|
||||
if ($row['CType'] === 'list' && $row['list_type'] === 'epproducts_hotel_teasergroup') {
|
||||
$flexFormData = $this->getFlexFormData($row);
|
||||
$drawItem = false;
|
||||
$countryUid = $flexFormData['settings']['countryUid'];
|
||||
$regionUid = $flexFormData['settings']['reguionUid'];
|
||||
$cityUid = $flexFormData['settings']['cityUid'];
|
||||
$name = '';
|
||||
if ((int) $cityUid > 0) {
|
||||
$name = $this->getName('city', $cityUid);
|
||||
} elseif ((int) $regionUid > 0) {
|
||||
$name = $this->getName('region', $regionUid);
|
||||
} elseif ((int) $countryUid > 0) {
|
||||
$name = $this->getName('country', $countryUid);
|
||||
}
|
||||
$itemContent = '<strong>Teasergruppe Hotels</strong><br />' . $name;
|
||||
}
|
||||
|
||||
// Hotel detail
|
||||
if ($row['CType'] === 'list' && $row['list_type'] === 'epproducts_hotel_detail') {
|
||||
$flexFormData = $this->getFlexFormData($row);
|
||||
$drawItem = false;
|
||||
$hotelUid = $flexFormData['settings']['hotelUid'];
|
||||
$name = $this->getName('hotel', $hotelUid);
|
||||
$itemContent = '<strong>Detailseite Hotel</strong><br />' . $name;
|
||||
}
|
||||
|
||||
// FAQ
|
||||
if ($row['CType'] === 'list' && $row['list_type'] === 'epproducts_faq') {
|
||||
$flexFormData = $this->getFlexFormData($row);
|
||||
$faqUids = GeneralUtility::trimExplode(',', $flexFormData['settings']['faqUids']);
|
||||
$drawItem = false;
|
||||
$itemContent = '<strong>FAQ</strong><br />' . count($faqUids) . ' Frage(n)';
|
||||
}
|
||||
|
||||
// Product pricetable
|
||||
if ($row['CType'] === 'list' && $row['list_type'] === 'epproducts_product_pricetable') {
|
||||
$flexFormData = $this->getFlexFormData($row);
|
||||
$drawItem = false;
|
||||
$itemContent = '<strong>Buchungstabelle</strong><br />';
|
||||
$productUid = $flexFormData['settings']['productUid'];
|
||||
$record = BackendUtility::getRecord('tx_epproducts_domain_model_product', $productUid);
|
||||
$itemContent .= $record['name'];
|
||||
$hotelUid = $flexFormData['settings']['hotelUid'];
|
||||
$record = BackendUtility::getRecord('tx_epproducts_domain_model_hotel', $hotelUid);
|
||||
$itemContent .= ', ' . $record['name'];
|
||||
}
|
||||
|
||||
// Product detail
|
||||
if ($row['CType'] === 'list' && $row['list_type'] === 'epproducts_product_detail') {
|
||||
$flexFormData = $this->getFlexFormData($row);
|
||||
$drawItem = false;
|
||||
$itemContent = '<strong>Produkt</strong><br />';
|
||||
$productUid = $flexFormData['settings']['productUid'];
|
||||
if ((int) $productUid === 0) {
|
||||
$itemContent .= 'allgemein';
|
||||
} else {
|
||||
$record = BackendUtility::getRecord('tx_epproducts_domain_model_product', $productUid);
|
||||
$itemContent .= $record['name_internal'] ? $record['name_internal'] : $record['name'];
|
||||
$hotelUid = $flexFormData['settings']['hotelUid'];
|
||||
if ((int) $hotelUid > 0) {
|
||||
$record = BackendUtility::getRecord('tx_epproducts_domain_model_hotel', $hotelUid);
|
||||
$itemContent .= ', ' . $record['name'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Product teaser
|
||||
if ($row['CType'] === 'list' && $row['list_type'] === 'epproducts_product_teasergroup') {
|
||||
$flexFormData = $this->getFlexFormData($row);
|
||||
$mode = $this->getMode($flexFormData);
|
||||
$drawItem = false;
|
||||
switch ($mode)
|
||||
{
|
||||
case 'teasergroup':
|
||||
$itemContent = '<strong>Teasergruppe Produkte</strong><br />';
|
||||
$filterParts = [];
|
||||
$countryUid = $flexFormData['settings']['countryUid'];
|
||||
if ((int) $countryUid > 0) {
|
||||
$record = BackendUtility::getRecord('tx_epproducts_domain_model_country', $countryUid);
|
||||
$filterParts[] = $record['name'];
|
||||
}
|
||||
$regionUid = $flexFormData['settings']['regionUid'];
|
||||
if ((int) $regionUid > 0) {
|
||||
$record = BackendUtility::getRecord('tx_epproducts_domain_model_region', $regionUid);
|
||||
$filterParts[] = $record['name'];
|
||||
}
|
||||
$conceptUid = $flexFormData['settings']['conceptUid'];
|
||||
if ((int) $conceptUid > 0) {
|
||||
$record = BackendUtility::getRecord('tx_epproducts_domain_model_concept', $conceptUid);
|
||||
$filterParts[] = $record['name'];
|
||||
}
|
||||
$hotelUid = $flexFormData['settings']['hotelUid'];
|
||||
if ((int) $hotelUid > 0) {
|
||||
$record = BackendUtility::getRecord('tx_epproducts_domain_model_hotel', $hotelUid);
|
||||
$filterParts[] = $record['name'];
|
||||
}
|
||||
if ($flexFormData['settings']['dateFrom']) {
|
||||
$filterParts[] = 'von ' . date('d.m.Y', $flexFormData['settings']['dateFrom']);
|
||||
}
|
||||
if ($flexFormData['settings']['dateTo']) {
|
||||
$filterParts[] = 'bis ' . date('d.m.Y', $flexFormData['settings']['dateTo']);
|
||||
}
|
||||
if ((bool) $flexFormData['settings']['busAvailable'] === true) {
|
||||
$filterParts[] = 'Busreisen';
|
||||
}
|
||||
$itemContent .= implode(', ', $filterParts);
|
||||
break;
|
||||
case 'single':
|
||||
$itemContent = '<strong>Teaser Produkt</strong><br />';
|
||||
$productUid = $flexFormData['settings']['productUid'];
|
||||
$record = BackendUtility::getRecord('tx_epproducts_domain_model_product', $productUid);
|
||||
$itemContent .= $record['name'];
|
||||
$hotelUid = $flexFormData['settings']['hotelUid'];
|
||||
if ((int) $hotelUid > 0) {
|
||||
$record = BackendUtility::getRecord('tx_epproducts_domain_model_hotel', $hotelUid);
|
||||
$itemContent .= ', ' . $record['name'];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $row
|
||||
* @return array
|
||||
*/
|
||||
protected function getFlexFormData(array $row)
|
||||
{
|
||||
/** @var FlexFormService $flexFormService */
|
||||
$flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
|
||||
return $flexFormService->convertFlexFormContentToArray($row['pi_flexform']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $flexFormData
|
||||
* @return string
|
||||
*/
|
||||
protected function getMode(array $flexFormData)
|
||||
{
|
||||
$controllerAction = $flexFormData['switchableControllerActions'];
|
||||
return substr($controllerAction, strpos($controllerAction, '>') + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @param integer $uid
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getName($type, $uid)
|
||||
{
|
||||
$record = BackendUtility::getRecord('tx_epproducts_domain_model_' . $type, $uid);
|
||||
return $record['name'];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Hooks;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Traits\DbConnectionTrait;
|
||||
use TYPO3\CMS\Core\DataHandling\DataHandler;
|
||||
use TYPO3\CMS\Core\Messaging\FlashMessage;
|
||||
use TYPO3\CMS\Core\Messaging\FlashMessageService;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Object\ObjectManager;
|
||||
|
||||
class Tcemain
|
||||
{
|
||||
use DbConnectionTrait;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tables = [
|
||||
'tx_epproducts_domain_model_country',
|
||||
'tx_epproducts_domain_model_region',
|
||||
'tx_epproducts_domain_model_city'
|
||||
];
|
||||
|
||||
/**
|
||||
* @param array $fields
|
||||
* @param string $table
|
||||
* @param int $id
|
||||
* @param DataHandler $obj
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
public function processDatamap_preProcessFieldArray(array &$fields, $table, $id, DataHandler $obj)
|
||||
{
|
||||
// Render flash message in case of duplicate entry
|
||||
if ($table === 'tx_epproducts_domain_model_matchcode' && $fields['code'] !== '') {
|
||||
$code = $fields['code'];
|
||||
$qb = $this->getDbConnection()->createQueryBuilder();
|
||||
$query = $qb
|
||||
->select('uid')
|
||||
->from('tx_epproducts_domain_model_matchcode')
|
||||
->where('code = :code')
|
||||
->andWhere('deleted = 0')
|
||||
->setParameter('code', $code)
|
||||
;
|
||||
if (is_numeric($id)) {
|
||||
$query
|
||||
->andWhere('uid != :uid')
|
||||
->setParameter('uid', $id)
|
||||
;
|
||||
}
|
||||
$existing = $query->execute()->fetch();
|
||||
if ($existing) {
|
||||
$this->addFlashMessage('Der Hotelcode ' . $code . ' ist schon vergeben worden.', 'Hinweis', FlashMessage::WARNING);
|
||||
}
|
||||
}
|
||||
if ($table === 'tx_epproducts_domain_model_product' && $fields['code'] !== '') {
|
||||
$code = $fields['code'];
|
||||
$qb = $this->getDbConnection()->createQueryBuilder();
|
||||
$query = $qb
|
||||
->select('uid')
|
||||
->from('tx_epproducts_domain_model_product')
|
||||
->where('code = :code')
|
||||
->andWhere('deleted = 0')
|
||||
->setParameter('code', $code);
|
||||
if (is_numeric($id)) {
|
||||
$query
|
||||
->andWhere('uid != :uid')
|
||||
->setParameter('uid', $id)
|
||||
;
|
||||
}
|
||||
$existing = $query->execute()->fetch();
|
||||
if ($existing) {
|
||||
$this->addFlashMessage('Der Productcode ' . $code . ' ist schon vergeben worden.', 'Hinweis', FlashMessage::WARNING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param string $title
|
||||
* @param int $severity
|
||||
*/
|
||||
protected function addFlashMessage($message, $title, $severity)
|
||||
{
|
||||
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
|
||||
/** @var \TYPO3\CMS\Core\Messaging\FlashMessageService $flashMessageService */
|
||||
$flashMessageService = $objectManager->get(FlashMessageService::class);
|
||||
$messageQueue = $flashMessageService->getMessageQueueByIdentifier();
|
||||
/** @var \TYPO3\CMS\Core\Messaging\FlashMessage $message */
|
||||
$message = GeneralUtility::makeInstance(FlashMessage::class, $message, $title, $severity, true);
|
||||
$messageQueue->addMessage($message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Middleware;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Symfony\Component\HttpFoundation\Cookie;
|
||||
|
||||
class StagingEnvironmentMiddleware implements MiddlewareInterface
|
||||
{
|
||||
private const COOKIE_NAME = 'ep_myep_staging';
|
||||
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
{
|
||||
$queryParams = $request->getQueryParams();
|
||||
|
||||
if (!isset($queryParams['ep_staging'])) {
|
||||
return $handler->handle($request);
|
||||
}
|
||||
|
||||
$isStaging = '1' === (string) $queryParams['ep_staging'];
|
||||
|
||||
// Update $_COOKIE so the value is available during the current request
|
||||
if ($isStaging) {
|
||||
$_COOKIE[self::COOKIE_NAME] = '1';
|
||||
} else {
|
||||
unset($_COOKIE[self::COOKIE_NAME]);
|
||||
}
|
||||
|
||||
$response = $handler->handle($request);
|
||||
|
||||
// Set the cookie on the response for subsequent browser requests
|
||||
if ($isStaging) {
|
||||
$cookie = new Cookie(self::COOKIE_NAME, '1', 0, '/', null, false, true, false, Cookie::SAMESITE_LAX);
|
||||
} else {
|
||||
$cookie = new Cookie(self::COOKIE_NAME, '', 1, '/', null, false, true, false, Cookie::SAMESITE_LAX);
|
||||
}
|
||||
|
||||
return $response->withAddedHeader('Set-Cookie', (string) $cookie);
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Middleware;
|
||||
|
||||
use EP\EpProducts\Service\FilterService;
|
||||
use EP\EpProducts\Service\FilterSettingsEncoder;
|
||||
use EP\EpProducts\Traits\DbConnectionTrait;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
|
||||
use TYPO3\CMS\Core\Http\NormalizedParams;
|
||||
use TYPO3\CMS\Core\Http\RedirectResponse;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
class StaticSearchParamsMiddleware implements MiddlewareInterface
|
||||
{
|
||||
use DbConnectionTrait;
|
||||
|
||||
public const PREFIX_PATH_SEGMENT = 'reiseauswahl';
|
||||
public const REDIRECT_RESPONSE_CODE = 302;
|
||||
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
{
|
||||
/** @var NormalizedParams $params */
|
||||
$params = $request->getAttribute('normalizedParams');
|
||||
$uri = $params->getRequestUri();
|
||||
|
||||
if (strpos($uri, self::PREFIX_PATH_SEGMENT) === false) {
|
||||
return $handler->handle($request);
|
||||
}
|
||||
|
||||
// Ensure trailing slash for comparison
|
||||
$uri = rtrim($uri, '/') . '/';
|
||||
|
||||
$qb = $this->getDbConnection()->createQueryBuilder();
|
||||
|
||||
$query = $qb
|
||||
->select('*')
|
||||
->from('tx_epproducts_domain_model_staticsearchparams')
|
||||
->where('CONCAT("/", :prefix, "/", path_segment, "/")=LOWER(:uri)')
|
||||
->andWhere('deleted = 0')
|
||||
->andWhere('hidden = 0')
|
||||
->setParameters([
|
||||
'prefix' => self::PREFIX_PATH_SEGMENT,
|
||||
'uri' => $uri,
|
||||
])
|
||||
;
|
||||
|
||||
$row = $query->execute()->fetchAssociative();
|
||||
|
||||
if (!$row) {
|
||||
return $handler->handle($request);
|
||||
}
|
||||
|
||||
$filterService = GeneralUtility::makeInstance(FilterService::class);
|
||||
|
||||
$filterSettings = $filterService->getFilterSettingsFromStaticSearchParams($row);
|
||||
$filterSettingsEncoder = new FilterSettingsEncoder();
|
||||
$encodedFilterSettings = $filterSettingsEncoder->encode($filterSettings);
|
||||
|
||||
$searchPageUid = GeneralUtility::makeInstance(ExtensionConfiguration::class)
|
||||
->get('ep_products', 'searchPageUid');
|
||||
|
||||
$site = $request->getAttribute('site');
|
||||
$redirectUri = $site->getRouter()->generateUri($searchPageUid, ['f' => $encodedFilterSettings]);
|
||||
|
||||
return new RedirectResponse($redirectUri, self::REDIRECT_RESPONSE_CODE);
|
||||
}
|
||||
}
|
||||
@@ -1,341 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Service;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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 Doctrine\DBAL\Connection;
|
||||
use EP\EpProducts\Domain\Model\Contingent;
|
||||
use EP\EpProducts\Traits\DbConnectionTrait;
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Psr\Log\LoggerAwareTrait;
|
||||
use TYPO3\CMS\Core\SingletonInterface;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
|
||||
|
||||
class ContingentImportService implements SingletonInterface, LoggerAwareInterface
|
||||
{
|
||||
use LoggerAwareTrait;
|
||||
use DbConnectionTrait;
|
||||
|
||||
public const XML_PATH = 'fileadmin/xmlexportzimmer';
|
||||
public const ROOMCODE_STATUS = 'BelKal';
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
// protected $ignoredRoomTypes = ['PDGS', 'TEAM'];
|
||||
protected $ignoredRoomTypes = ['PDGS'];
|
||||
|
||||
/**
|
||||
* @var ConfigurationManagerInterface
|
||||
*/
|
||||
protected $configurationManager;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $contingentsPid = 0;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $hotelsPid = 0;
|
||||
|
||||
/**
|
||||
* @var Connection
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
public function __construct(ConfigurationManagerInterface $manager)
|
||||
{
|
||||
$this->configurationManager = $manager;
|
||||
|
||||
$settings = GeneralUtility::removeDotsFromTS(
|
||||
$this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT)
|
||||
);
|
||||
|
||||
if (isset($settings['plugin']['tx_epproducts']['persistence']['storagePid'])) {
|
||||
$this->contingentsPid = $settings['plugin']['tx_epproducts']['persistence']['storagePid'];
|
||||
} elseif (isset($settings['module']['tx_epproducts']['persistence']['storagePid'])) {
|
||||
$this->contingentsPid = $settings['module']['tx_epproducts']['persistence']['storagePid'];
|
||||
}
|
||||
|
||||
if (isset($settings['plugin']['tx_epproducts']['settings']['hotelsPid'])) {
|
||||
$this->hotelsPid = $settings['plugin']['tx_epproducts']['settings']['hotelsPid'];
|
||||
} elseif (isset($settings['module']['tx_epproducts']['settings']['hotelsPid'])) {
|
||||
$this->hotelsPid = $settings['module']['tx_epproducts']['settings']['hotelsPid'];
|
||||
}
|
||||
|
||||
$this->db = $this->getDbConnection();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
public function import()
|
||||
{
|
||||
$this->createTempTable();
|
||||
$this->logger->info('starting product import');
|
||||
$contingentCount = $this->parseXmlFilesInFolder();
|
||||
$this->clearTable();
|
||||
$this->copyTable();
|
||||
$this->clearTempTable();
|
||||
|
||||
return $contingentCount;
|
||||
}
|
||||
|
||||
public function isImportRequired(): bool
|
||||
{
|
||||
$timestampService = new ImportTimestampService();
|
||||
|
||||
return $timestampService->isImportRequired(
|
||||
'fileadmin/xmlexportzimmer/uebertragung.info',
|
||||
'fileadmin/contingents_import.info'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function parseXmlFilesInFolder()
|
||||
{
|
||||
$dateCount = 0;
|
||||
$path = GeneralUtility::getFileAbsFileName(self::XML_PATH);
|
||||
$folder = opendir($path);
|
||||
while (($fileName = readdir($folder)) !== false) {
|
||||
if (0 === strpos($fileName, 'HotelZimmer')) {
|
||||
$dateCount += $this->parseContingentXmlFile($path, $fileName);
|
||||
}
|
||||
}
|
||||
|
||||
return $dateCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function parseContingentXmlFile($path, $fileName)
|
||||
{
|
||||
$filePath = sprintf('%s/%s', $path, $fileName);
|
||||
|
||||
if (null === $xmlData = $this->loadXmlFile($filePath)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $this->parseContingent($xmlData);
|
||||
}
|
||||
|
||||
public function loadXmlFile($file): ?\SimpleXMLElement
|
||||
{
|
||||
libxml_use_internal_errors(true);
|
||||
if (!file_exists($file)) {
|
||||
return null;
|
||||
}
|
||||
/** @var \SimpleXMLElement $xmlData */
|
||||
if (!$xmlData = simplexml_load_string(file_get_contents($file))) {
|
||||
libxml_clear_errors();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return $xmlData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
public function createTempTable()
|
||||
{
|
||||
$this->db->executeStatement('CREATE TABLE IF NOT EXISTS tx_epproducts_domain_model_contingent_temp LIKE tx_epproducts_domain_model_contingent');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
public function clearTable()
|
||||
{
|
||||
$this->db->executeStatement('TRUNCATE TABLE tx_epproducts_domain_model_contingent');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
public function copyTable()
|
||||
{
|
||||
$this->db->executeStatement('INSERT INTO tx_epproducts_domain_model_contingent SELECT * FROM tx_epproducts_domain_model_contingent_temp');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
public function clearTempTable()
|
||||
{
|
||||
$this->db->executeStatement('TRUNCATE TABLE tx_epproducts_domain_model_contingent_temp');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function parseContingent(\SimpleXMLElement $xmlContingent)
|
||||
{
|
||||
$hotelCode = (string) $xmlContingent['code'];
|
||||
$sql = 'SELECT h.uid uid
|
||||
FROM tx_epproducts_domain_model_hotel h
|
||||
WHERE h.deleted = 0 AND h.hidden = 0 AND h.code = :code AND h.pid = :pid
|
||||
LIMIT 0,1';
|
||||
$hotelData = $this->db->fetchAssociative($sql, ['code' => $hotelCode, 'pid' => $this->hotelsPid]);
|
||||
|
||||
// Skip import in case hotel can't be found
|
||||
if (false === $hotelData) {
|
||||
$this->logger->warning('hotel not found', ['code' => $hotelCode]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$hotelData['busProId'] = (string) $xmlContingent['idbuspro'];
|
||||
$hotelData['code'] = (string) $xmlContingent['code'];
|
||||
|
||||
if ($xmlContingent->idbuspro_kontingent_aus) {
|
||||
$linkedProductId = (int) $xmlContingent->idbuspro_kontingent_aus;
|
||||
$path = GeneralUtility::getFileAbsFileName(self::XML_PATH);
|
||||
if (null === $xmlContingent = $this->loadXmlFile(sprintf('%s/HotelZimmer_%d.xml', $path, $linkedProductId))) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($xmlContingent->kapazitaeten)) {
|
||||
$this->logger->warning('hotel has no contingents', ['code' => $hotelCode]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$roomTypes = $this->parseRoomTypes($xmlContingent->unterbringungen);
|
||||
|
||||
return $this->parseRooms($xmlContingent->kapazitaeten, $hotelData, $roomTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \SimpleXMLElement $xmlTypes
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function parseRoomTypes($xmlTypes)
|
||||
{
|
||||
$types = [];
|
||||
foreach ($xmlTypes->unterbringung as $xmlType) {
|
||||
$idBusPro = (string) $xmlType['idbuspro'];
|
||||
$code = (string) $xmlType['code'];
|
||||
$types[] = [
|
||||
'idBusPro' => $idBusPro,
|
||||
'link' => isset($xmlType['idbuspro_kontingent_aus']) ? (string) $xmlType['idbuspro_kontingent_aus'] : null,
|
||||
'pax' => (int) $xmlType['pax_max'],
|
||||
'code' => $code,
|
||||
'label' => (string) $xmlType['zimmerbezeichnung'],
|
||||
'ctrl' => self::ROOMCODE_STATUS === $code,
|
||||
];
|
||||
}
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \SimpleXMLElement|\SimpleXMLElement[] $xmlDates
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function parseRooms(\SimpleXMLElement $xmlDates, array $hotelData, array $roomTypes)
|
||||
{
|
||||
$dateCount = 0;
|
||||
foreach ($xmlDates->kapazitaet as $xmlDate) {
|
||||
$date = \DateTime::createFromFormat('d.m.Y', (string) $xmlDate['termin']);
|
||||
foreach ($roomTypes as $roomType) {
|
||||
$roomCode = $roomType['code'];
|
||||
if (in_array($roomCode, $this->ignoredRoomTypes, true)) {
|
||||
continue;
|
||||
}
|
||||
$roomTypeBusProId = $roomType['link'] ?: $roomType['idBusPro'];
|
||||
$xpath = sprintf('zimmerliste/zimmer[@idbuspro="%d"]', $roomTypeBusProId);
|
||||
$xmlRoom = $xmlDate->xpath($xpath)[0];
|
||||
if (null === $xmlRoom) {
|
||||
continue;
|
||||
}
|
||||
$this->calculateContingent($xmlRoom, $roomType, $date, $hotelData);
|
||||
}
|
||||
++$dateCount;
|
||||
}
|
||||
|
||||
return $dateCount;
|
||||
}
|
||||
|
||||
protected function calculateContingent(\SimpleXMLElement $xmlRoom, array $roomType, \DateTime $date, array $hotelData): void
|
||||
{
|
||||
$availablePax = 0;
|
||||
$capacity = 0;
|
||||
$status = Contingent::STATUS_OK;
|
||||
$isControlRoom = true === $roomType['ctrl'];
|
||||
if ($isControlRoom && 'A' === (string) $xmlRoom['status']) {
|
||||
$status = Contingent::STATUS_ONREQUEST;
|
||||
} elseif ($isControlRoom && 'S' === (string) $xmlRoom['status']) {
|
||||
$status = Contingent::STATUS_BLOCKED;
|
||||
} else {
|
||||
$capacity = (int) $xmlRoom['kontingent'] * (int) $roomType['pax'];
|
||||
$availableRooms = (int) $xmlRoom['frei'] > 0 ? (int) $xmlRoom['frei'] : 0;
|
||||
$availablePax = $availableRooms * $roomType['pax'];
|
||||
}
|
||||
$minPrice = (int) $xmlRoom['abpreis'];
|
||||
$minNights = (int) $xmlRoom['abpreis_naechte'];
|
||||
$additionalNightMinPrice = (int) $xmlRoom['abpreis_verlaengerung'];
|
||||
$additionalNightMinNights = (int) $xmlRoom['abpreis_verlaengerung_naechte'];
|
||||
$roomLabel = $roomType['label'];
|
||||
$this->db->insert(
|
||||
'tx_epproducts_domain_model_contingent_temp',
|
||||
[
|
||||
'pid' => $this->contingentsPid,
|
||||
'hotel' => $hotelData['uid'],
|
||||
'hotel_code' => $hotelData['code'],
|
||||
'hotel_bus_pro_id' => $hotelData['busProId'],
|
||||
'room_code' => $roomType['code'],
|
||||
'room_label' => $roomLabel,
|
||||
'pax' => $capacity,
|
||||
'available' => $availablePax,
|
||||
'status' => $status,
|
||||
'date' => $date->format('Y-m-d'),
|
||||
'min_price' => $minPrice,
|
||||
'min_nights' => $minNights,
|
||||
'additional_night_min_price' => $additionalNightMinPrice,
|
||||
'additional_night_min_nights' => $additionalNightMinNights,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -112,9 +112,9 @@ class DateImportService implements SingletonInterface, LoggerAwareInterface
|
||||
protected $cacheService;
|
||||
|
||||
/**
|
||||
* @var ProductImportSourceFactory
|
||||
* @var ProductImportSource
|
||||
*/
|
||||
protected $importSourceFactory;
|
||||
protected $importSource;
|
||||
|
||||
/**
|
||||
* @var RoomTypeResolver
|
||||
@@ -131,18 +131,18 @@ class DateImportService implements SingletonInterface, LoggerAwareInterface
|
||||
/**
|
||||
* @param ConfigurationManagerInterface $configurationManager
|
||||
* @param CacheService $cacheService
|
||||
* @param ProductImportSourceFactory $importSourceFactory
|
||||
* @param ProductImportSource $importSource
|
||||
* @param RoomTypeResolver $roomTypeResolver
|
||||
*/
|
||||
public function __construct(
|
||||
ConfigurationManagerInterface $configurationManager,
|
||||
CacheService $cacheService,
|
||||
ProductImportSourceFactory $importSourceFactory,
|
||||
ProductImportSource $importSource,
|
||||
RoomTypeResolver $roomTypeResolver
|
||||
) {
|
||||
$this->configurationManager = $configurationManager;
|
||||
$this->cacheService = $cacheService;
|
||||
$this->importSourceFactory = $importSourceFactory;
|
||||
$this->importSource = $importSource;
|
||||
$this->roomTypeResolver = $roomTypeResolver;
|
||||
|
||||
$settings = GeneralUtility::removeDotsFromTS(
|
||||
@@ -179,7 +179,7 @@ class DateImportService implements SingletonInterface, LoggerAwareInterface
|
||||
|
||||
public function isImportRequired(): bool
|
||||
{
|
||||
return $this->importSourceFactory->get()->isNewImportAvailable();
|
||||
return $this->importSource->isNewImportAvailable();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
<?php
|
||||
namespace EP\EpProducts\Service;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2020 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 Symfony\Component\Mime\Address;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use TYPO3\CMS\Core\Mail\FluidEmail;
|
||||
use TYPO3\CMS\Core\Mail\Mailer;
|
||||
use TYPO3\CMS\Core\SingletonInterface;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
|
||||
|
||||
class EmailService implements SingletonInterface
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $settings;
|
||||
|
||||
public function __construct(ConfigurationManagerInterface $manager)
|
||||
{
|
||||
$settings = GeneralUtility::removeDotsFromTS(
|
||||
$manager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT)
|
||||
);
|
||||
$this->settings = $settings['plugin']['tx_eptheme'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
* @param array $variables
|
||||
* @return bool
|
||||
*/
|
||||
public function send(array $options, array $variables)
|
||||
{
|
||||
$resolvedOptions = $this->resolveOptions($options);
|
||||
|
||||
/** @var FluidEmail $email */
|
||||
$email = GeneralUtility::makeInstance(FluidEmail::class);
|
||||
$email
|
||||
->to(new Address($resolvedOptions['toEmail'], $resolvedOptions['toName']))
|
||||
->from(new Address($resolvedOptions['fromEmail'], $resolvedOptions['fromName']))
|
||||
->subject($resolvedOptions['subject'])
|
||||
->setTemplate($resolvedOptions['templateName'])
|
||||
->assignMultiple($variables)
|
||||
;
|
||||
|
||||
GeneralUtility::makeInstance(Mailer::class)->send($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
* @return array
|
||||
*/
|
||||
protected function resolveOptions(array $options)
|
||||
{
|
||||
$optionsResolver = new OptionsResolver();
|
||||
$optionsResolver->setDefined(['toEmail', 'toName', 'subject', 'templateName', 'fromEmail', 'fromName']);
|
||||
$optionsResolver->setRequired(['toEmail', 'toName', 'subject', 'templateName']);
|
||||
$optionsResolver->setDefaults([
|
||||
'fromEmail' => $this->settings['settings']['contactFormToEmail'],
|
||||
'fromName' => $this->settings['settings']['contactFormToName'],
|
||||
]);
|
||||
|
||||
return $optionsResolver->resolve($options);
|
||||
}
|
||||
}
|
||||
@@ -1,267 +0,0 @@
|
||||
<?php
|
||||
namespace EP\EpProducts\Service;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2020 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\BpnConnect\ApiClient;
|
||||
use EP\EpProducts\Domain\Repository\HotelRepository;
|
||||
use League\Period\Period;
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Psr\Log\LoggerAwareTrait;
|
||||
use Symfony\Component\HttpClient\HttpClient;
|
||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||
use TYPO3\CMS\Core\SingletonInterface;
|
||||
|
||||
class GroupsSwissService implements SingletonInterface, LoggerAwareInterface
|
||||
{
|
||||
use LoggerAwareTrait;
|
||||
|
||||
/**
|
||||
* @var HotelRepository
|
||||
*/
|
||||
protected $hotelRepository;
|
||||
|
||||
/**
|
||||
* @var ApiClient
|
||||
*/
|
||||
protected $apiClient;
|
||||
|
||||
/**
|
||||
* @var HttpClient
|
||||
*/
|
||||
protected $httpClient;
|
||||
|
||||
/**
|
||||
* @param HotelRepository $hotelRepository
|
||||
* @param ApiClient $apiClient
|
||||
*/
|
||||
public function __construct(HotelRepository $hotelRepository, ApiClient $apiClient)
|
||||
{
|
||||
$this->hotelRepository = $hotelRepository;
|
||||
$this->apiClient = $apiClient;
|
||||
$this->httpClient = HttpClient::create();
|
||||
}
|
||||
|
||||
public function publishContingents(int $hotelUid, int $houseNumber, string $apiKey): bool
|
||||
{
|
||||
$range = Period::after(new \DateTime('now'), '1 year');
|
||||
|
||||
$hotel = $this->hotelRepository->findByIdentifier($hotelUid);
|
||||
|
||||
if (null === $hotel) {
|
||||
$this->logger->error(sprintf('Hotel with uid %d not found', $hotelUid));
|
||||
return false;
|
||||
}
|
||||
|
||||
$hotelCode = trim((string) $hotel->getCode());
|
||||
if ('' === $hotelCode) {
|
||||
$this->logger->error(sprintf('Hotel with uid %d has no hotel code', $hotelUid));
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$calendar = $this->apiClient->getCalendar(
|
||||
$hotelCode,
|
||||
\DateTime::createFromImmutable($range->getStartDate()),
|
||||
\DateTime::createFromImmutable($range->getEndDate()->sub(new \DateInterval('P1D')))
|
||||
);
|
||||
$calendarRows = isset($calendar['data']) && is_array($calendar['data']) ? $calendar['data'] : [];
|
||||
} catch (\Throwable $e) {
|
||||
$this->logger->error(sprintf('No dates found for hotel with uid %d', $hotelUid), ['exception' => $e]);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->resetChart($range, $apiKey, $houseNumber);
|
||||
|
||||
$this->generateChart(
|
||||
$calendarRows,
|
||||
$apiKey,
|
||||
$houseNumber
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Period $range
|
||||
* @param string $apiKey
|
||||
* @param string $houseNumber
|
||||
*/
|
||||
protected function resetChart(Period $range, $apiKey, $houseNumber): void
|
||||
{
|
||||
$item = [
|
||||
'from' => $range->getStartDate(),
|
||||
'to' => $range->getEndDate(),
|
||||
];
|
||||
|
||||
$this->addItem($item, 0, $apiKey, $houseNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $calendarRows
|
||||
* @param string $apiKey
|
||||
* @param int $houseNumber
|
||||
*/
|
||||
protected function generateChart(array $calendarRows, $apiKey, $houseNumber): void
|
||||
{
|
||||
usort($calendarRows, function (array $left, array $right): int {
|
||||
return strcmp((string) ($left['date'] ?? ''), (string) ($right['date'] ?? ''));
|
||||
});
|
||||
|
||||
$item = null;
|
||||
$itemStatus = null;
|
||||
$lastDate = null;
|
||||
|
||||
foreach ($calendarRows as $row) {
|
||||
if (!isset($row['date'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$currentDate = new \DateTimeImmutable($row['date']);
|
||||
$currentStatus = $this->normalizeStatus((string) ($row['status'] ?? 'OK'));
|
||||
|
||||
if (null !== $lastDate && $currentDate > $lastDate->add(new \DateInterval('P1D'))) {
|
||||
if (null !== $item) {
|
||||
$this->addItem($item, $this->translateStatusToGroupsSwissState($itemStatus), $apiKey, $houseNumber);
|
||||
$item = null;
|
||||
$itemStatus = null;
|
||||
}
|
||||
}
|
||||
|
||||
if ('OK' === $currentStatus) {
|
||||
if (null !== $item) {
|
||||
$item['to'] = $lastDate;
|
||||
$this->addItem($item, $this->translateStatusToGroupsSwissState($itemStatus), $apiKey, $houseNumber);
|
||||
$item = null;
|
||||
$itemStatus = null;
|
||||
}
|
||||
$lastDate = $currentDate;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (null === $item) {
|
||||
$item = [
|
||||
'from' => $currentDate,
|
||||
'to' => $currentDate,
|
||||
];
|
||||
$itemStatus = $currentStatus;
|
||||
} elseif ($itemStatus !== $currentStatus) {
|
||||
$item['to'] = $lastDate;
|
||||
$this->addItem($item, $this->translateStatusToGroupsSwissState($itemStatus), $apiKey, $houseNumber);
|
||||
$item = [
|
||||
'from' => $currentDate,
|
||||
'to' => $currentDate,
|
||||
];
|
||||
$itemStatus = $currentStatus;
|
||||
} else {
|
||||
$item['to'] = $currentDate;
|
||||
}
|
||||
|
||||
$lastDate = $currentDate;
|
||||
}
|
||||
|
||||
if (null !== $item) {
|
||||
$item['to'] = $lastDate;
|
||||
$this->addItem($item, $this->translateStatusToGroupsSwissState($itemStatus), $apiKey, $houseNumber);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $item
|
||||
* @param int $status
|
||||
* @param string $apiKey
|
||||
* @param int $houseNumber
|
||||
*/
|
||||
protected function addItem(array $item, $status, $apiKey, $houseNumber): void
|
||||
{
|
||||
$from = $item['from']->format('Y-m-d');
|
||||
$to = $item['to']->format('Y-m-d');
|
||||
|
||||
$this->logger->info(sprintf(
|
||||
'Adding status %d in %s-%s for %s',
|
||||
$status,
|
||||
$from,
|
||||
$to,
|
||||
$houseNumber
|
||||
));
|
||||
|
||||
try {
|
||||
$response = $this
|
||||
->httpClient
|
||||
->request('GET', 'https://www.groups.swiss/api/1.0/json.php', [
|
||||
'query' => [
|
||||
'apiKey' => $apiKey,
|
||||
'method' => 'setAvailabilityChart',
|
||||
'house' => $houseNumber,
|
||||
'from' => $from,
|
||||
'till' => $to,
|
||||
'state' => $status,
|
||||
],
|
||||
])
|
||||
;
|
||||
$this->logger->info($response->getContent());
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$this->logger->error(sprintf('A problem occured: %s', $e->getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $status
|
||||
* @return string
|
||||
*/
|
||||
protected function normalizeStatus(string $status): string
|
||||
{
|
||||
$status = strtoupper(trim($status));
|
||||
if ('ONREQUEST' === $status) {
|
||||
return 'ON_REQUEST';
|
||||
}
|
||||
|
||||
if (in_array($status, [ 'OK', 'ON_REQUEST', 'BLOCKED' ], true)) {
|
||||
return $status;
|
||||
}
|
||||
|
||||
return 'OK';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $status
|
||||
* @return int
|
||||
*/
|
||||
protected function translateStatusToGroupsSwissState(string $status): int
|
||||
{
|
||||
$status = $this->normalizeStatus($status);
|
||||
|
||||
if ('ON_REQUEST' === $status) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ('BLOCKED' === $status) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Service;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2020 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\BpnConnect\ApiClient;
|
||||
use EP\EpProducts\Domain\Model\Hotel;
|
||||
use Kigkonsult\Icalcreator\Vcalendar;
|
||||
use TYPO3\CMS\Core\SingletonInterface;
|
||||
|
||||
class IcalService implements SingletonInterface
|
||||
{
|
||||
private const SUMMARY_UNAVAILABLE = 'Unavailable';
|
||||
|
||||
/**
|
||||
* @var ApiClient
|
||||
*/
|
||||
protected $apiClient;
|
||||
|
||||
/**
|
||||
* @var Vcalendar
|
||||
*/
|
||||
protected $vcalendar;
|
||||
|
||||
/**
|
||||
* @param ApiClient $apiClient
|
||||
*/
|
||||
public function __construct(ApiClient $apiClient)
|
||||
{
|
||||
$this->apiClient = $apiClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Hotel $hotel
|
||||
* @return string
|
||||
*/
|
||||
public function createContingentsFeed(Hotel $hotel): string
|
||||
{
|
||||
$calendarRows = [];
|
||||
$hotelCode = trim((string) $hotel->getCode());
|
||||
|
||||
if ($hotelCode !== '') {
|
||||
$dateFrom = new \DateTimeImmutable('today');
|
||||
|
||||
try {
|
||||
$calendar = $this->apiClient->getCalendar(
|
||||
$hotelCode,
|
||||
$dateFrom,
|
||||
null,
|
||||
ApiClient::CALENDAR_MODE_RANGES
|
||||
);
|
||||
$calendarRows = isset($calendar['data']) && is_array($calendar['data']) ? $calendar['data'] : [];
|
||||
} catch (\Throwable $e) {
|
||||
$calendarRows = [];
|
||||
}
|
||||
}
|
||||
|
||||
$this->createCalendarInstance();
|
||||
$this->generateUnavailableItems($calendarRows);
|
||||
|
||||
try {
|
||||
return $this->vcalendar->vtimezonePopulate()->createCalendar();
|
||||
} catch (\Exception $e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $calendarRows
|
||||
*/
|
||||
protected function generateUnavailableItems(array $calendarRows): void
|
||||
{
|
||||
usort($calendarRows, function (array $left, array $right): int {
|
||||
return strcmp((string) ($left['date_from'] ?? ''), (string) ($right['date_from'] ?? ''));
|
||||
});
|
||||
|
||||
foreach ($calendarRows as $row) {
|
||||
if (!isset($row['date_from'], $row['date_to'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$this->isUnavailableStatus($row['status'] ?? 'OK')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$dateFrom = new \DateTimeImmutable($row['date_from']);
|
||||
$dateTo = new \DateTimeImmutable($row['date_to']);
|
||||
|
||||
if ($dateTo < $dateFrom) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->addBlockedItem([
|
||||
'from' => $dateFrom,
|
||||
'to' => $dateTo->add(new \DateInterval('P1D')),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $item
|
||||
*/
|
||||
protected function addBlockedItem(array $item): void
|
||||
{
|
||||
try {
|
||||
$this->vcalendar
|
||||
->newVevent()
|
||||
->setDtstart($item['from'])
|
||||
->setDtend($item['to'])
|
||||
->setSummary(self::SUMMARY_UNAVAILABLE)
|
||||
;
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $status
|
||||
* @return bool
|
||||
*/
|
||||
protected function isUnavailableStatus($status): bool
|
||||
{
|
||||
$status = strtoupper(trim((string) $status));
|
||||
|
||||
return in_array($status, [ 'BLOCKED', 'ON_REQUEST', 'ONREQUEST' ], true);
|
||||
}
|
||||
|
||||
protected function createCalendarInstance(): void
|
||||
{
|
||||
$this->vcalendar = Vcalendar::factory([ Vcalendar::UNIQUE_ID => 'www.ep-reisen.de' ]);
|
||||
$this->vcalendar->setXprop(
|
||||
Vcalendar::X_WR_TIMEZONE,
|
||||
'Europe/Berlin'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Service;
|
||||
|
||||
use TYPO3\CMS\Core\Log\LogManager;
|
||||
use TYPO3\CMS\Core\SingletonInterface;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Legacy import source: the busProNet exporter drops the XML files straight into
|
||||
* fileadmin/xmlexport/ (historically via pure-ftpd on the server). Kept as an
|
||||
* opt-in fallback so the import can run without the SFTP pull — selected with the
|
||||
* `productImportSource = local` extension configuration switch.
|
||||
*/
|
||||
final class LocalImportSource implements ProductImportSource, SingletonInterface
|
||||
{
|
||||
private const XML_DIR = 'fileadmin/xmlexport';
|
||||
private const UPLOAD_MARKER = 'fileadmin/xmlexport/uebertragung.info';
|
||||
private const IMPORT_MARKER = 'fileadmin/products_import.info';
|
||||
|
||||
public function acquire(): ?ProductImport
|
||||
{
|
||||
if (!$this->isNewImportAvailable()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$path = GeneralUtility::getFileAbsFileName(self::XML_DIR);
|
||||
$reader = new XmlProductReader(
|
||||
$path,
|
||||
GeneralUtility::makeInstance(LogManager::class)->getLogger(XmlProductReader::class)
|
||||
);
|
||||
|
||||
return new ProductImport($reader, $reader->getSourceGeneratedAt(), $path);
|
||||
}
|
||||
|
||||
public function markImported(ProductImport $import): void
|
||||
{
|
||||
(new ImportTimestampService())->writeImportTimestamp(self::IMPORT_MARKER);
|
||||
}
|
||||
|
||||
public function isNewImportAvailable(): bool
|
||||
{
|
||||
$timestampService = new ImportTimestampService();
|
||||
|
||||
$uploadMarkerPath = GeneralUtility::getFileAbsFileName(self::UPLOAD_MARKER);
|
||||
if ($uploadMarkerPath === '' || !is_file($uploadMarkerPath)) {
|
||||
// No supplier marker at all: import whatever is in the folder (legacy behaviour).
|
||||
return true;
|
||||
}
|
||||
|
||||
$uploadedAt = $timestampService->readImportTimestamp(self::UPLOAD_MARKER);
|
||||
$lastImportedAt = $timestampService->readImportTimestamp(self::IMPORT_MARKER);
|
||||
|
||||
return $uploadedAt === null || $lastImportedAt === null || $uploadedAt > $lastImportedAt;
|
||||
}
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
<?php
|
||||
namespace EP\EpProducts\Service;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Domain\Model\Dto\FilterOptions;
|
||||
use EP\EpProducts\Traits\DbConnectionTrait;
|
||||
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
||||
use TYPO3\CMS\Core\SingletonInterface;
|
||||
|
||||
class LogService implements SingletonInterface
|
||||
{
|
||||
use DbConnectionTrait;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
public function dumpSearchLogEpreisen()
|
||||
{
|
||||
$qb = $this->getDbConnection()->createQueryBuilder();
|
||||
|
||||
$result = $qb
|
||||
->select('logs.data as data')
|
||||
->addSelectLiteral('DATE_FORMAT(FROM_UNIXTIME(logs.time_micro), "%d.%m.%Y, %H:%i Uhr") as date')
|
||||
->from('tx_epproducts_log', 'logs')
|
||||
->orderBy('time_micro')
|
||||
->execute()
|
||||
->fetchAll()
|
||||
;
|
||||
|
||||
$csv = [
|
||||
[
|
||||
'Datum/Uhrzeit',
|
||||
'Destinationstyp',
|
||||
'Destinationsname',
|
||||
'Konzept',
|
||||
'Preisbereich',
|
||||
'Personenzahl',
|
||||
'Startdatum',
|
||||
'Enddatum',
|
||||
'Seite',
|
||||
'Seiten ID',
|
||||
],
|
||||
];
|
||||
|
||||
$labels = $this->fetchEntityLabels();
|
||||
|
||||
foreach ($result as $row)
|
||||
{
|
||||
$data = json_decode(substr($row['data'], 2));
|
||||
$searchParams = $data->searchParams;
|
||||
$priceRange = null;
|
||||
if ($searchParams->priceRange) {
|
||||
list ($priceFrom, $priceTo) = FilterOptions::$priceRangeOptions[$searchParams->priceRange];
|
||||
$priceRange = sprintf('%s - %s', $priceFrom, $priceTo);
|
||||
}
|
||||
$pageTitle = '';
|
||||
if ($searchParams->pageUid) {
|
||||
$page = BackendUtility::getRecord('pages', $searchParams->pageUid);
|
||||
$pageTitle = $page['title'];
|
||||
}
|
||||
$csv[] = [
|
||||
$row['date'],
|
||||
$searchParams->destinationType,
|
||||
$labels[$searchParams->destinationType][$searchParams->destinationUid],
|
||||
$labels['concept'][$searchParams->conceptUid],
|
||||
$priceRange,
|
||||
$searchParams->pax,
|
||||
$searchParams->dateFrom,
|
||||
$searchParams->dateTo,
|
||||
$pageTitle,
|
||||
$searchParams->pageUid,
|
||||
];
|
||||
}
|
||||
|
||||
return $csv;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
public function dumpSearchLogEpevents()
|
||||
{
|
||||
$qb = $this->getDbConnection()->createQueryBuilder();
|
||||
|
||||
$result = $qb
|
||||
->select('logs.data as data')
|
||||
->addSelectLiteral('DATE_FORMAT(FROM_UNIXTIME(logs.time_micro), "%d.%m.%Y, %H:%i Uhr") as date')
|
||||
->from('tx_epevents_log', 'logs')
|
||||
->orderBy('time_micro')
|
||||
->execute()
|
||||
->fetchAll()
|
||||
;
|
||||
|
||||
$csv = [
|
||||
[
|
||||
'Datum/Uhrzeit',
|
||||
'Suchbegriff',
|
||||
'Seite',
|
||||
'Seiten ID',
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($result as $row)
|
||||
{
|
||||
$data = json_decode(substr($row['data'], 2));
|
||||
$pageTitle = '';
|
||||
if ($data->pageUid) {
|
||||
$page = BackendUtility::getRecord('pages', $data->pageUid);
|
||||
$pageTitle = $page['title'];
|
||||
}
|
||||
$csv[] = [
|
||||
$row['date'],
|
||||
$data->search,
|
||||
$pageTitle,
|
||||
$data->pageUid,
|
||||
];
|
||||
}
|
||||
|
||||
return $csv;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
private function fetchEntityLabels()
|
||||
{
|
||||
$labels = [
|
||||
'country' => [],
|
||||
'region' => [],
|
||||
];
|
||||
|
||||
$qb = $this->getDbConnection()->createQueryBuilder();
|
||||
|
||||
$result = $qb
|
||||
->select('uid', 'name')
|
||||
->from('tx_epproducts_domain_model_country', 'c')
|
||||
->execute()
|
||||
->fetchAll()
|
||||
;
|
||||
|
||||
foreach ($result as $row)
|
||||
{
|
||||
$labels['country'][$row['uid']] = $row['name'];
|
||||
}
|
||||
|
||||
$qb = $this->getDbConnection()->createQueryBuilder();
|
||||
|
||||
$result = $qb
|
||||
->select('uid', 'name')
|
||||
->from('tx_epproducts_domain_model_region')
|
||||
->execute()
|
||||
->fetchAll()
|
||||
;
|
||||
|
||||
foreach ($result as $row)
|
||||
{
|
||||
$labels['region'][$row['uid']] = $row['name'];
|
||||
}
|
||||
|
||||
$qb = $this->getDbConnection()->createQueryBuilder();
|
||||
|
||||
$result = $qb
|
||||
->select('uid', 'name')
|
||||
->from('tx_epproducts_domain_model_concept')
|
||||
->execute()
|
||||
->fetchAll()
|
||||
;
|
||||
|
||||
foreach ($result as $row)
|
||||
{
|
||||
$labels['concept'][$row['uid']] = $row['name'];
|
||||
}
|
||||
|
||||
return $labels;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Service;
|
||||
|
||||
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
|
||||
use TYPO3\CMS\Core\SingletonInterface;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Picks the product import source based on the `productImportSource` extension
|
||||
* configuration switch: `sftp` (default) pulls from the remote SFTP server,
|
||||
* `local` reads the legacy fileadmin/xmlexport/ drop directory, `api` reads the
|
||||
* product export of the MyE&P API.
|
||||
*/
|
||||
final class ProductImportSourceFactory implements SingletonInterface
|
||||
{
|
||||
public const MODE_SFTP = 'sftp';
|
||||
public const MODE_LOCAL = 'local';
|
||||
public const MODE_API = 'api';
|
||||
|
||||
public function get(): ProductImportSource
|
||||
{
|
||||
$mode = $this->getMode();
|
||||
if ($mode === self::MODE_LOCAL) {
|
||||
return GeneralUtility::makeInstance(LocalImportSource::class);
|
||||
}
|
||||
if ($mode === self::MODE_API) {
|
||||
return GeneralUtility::makeInstance(ApiImportSource::class);
|
||||
}
|
||||
|
||||
return GeneralUtility::makeInstance(SftpImportSource::class);
|
||||
}
|
||||
|
||||
public function getMode(): string
|
||||
{
|
||||
$config = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('ep_products');
|
||||
$mode = strtolower(trim((string)(is_array($config) ? ($config['productImportSource'] ?? '') : '')));
|
||||
|
||||
return in_array($mode, [self::MODE_LOCAL, self::MODE_API], true) ? $mode : self::MODE_SFTP;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Service;
|
||||
|
||||
class SftpImportException extends \RuntimeException
|
||||
{
|
||||
}
|
||||
@@ -1,540 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Service;
|
||||
|
||||
use phpseclib3\Net\SFTP;
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Psr\Log\LoggerAwareTrait;
|
||||
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\SingletonInterface;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Pulls the busProNet product export (Ziel_*.xml, zustiege.xml, uebertragung.info)
|
||||
* from a remote SFTP server into a local staging directory and reads it through
|
||||
* an {@see XmlProductReader}.
|
||||
*
|
||||
* Change detection compares the remote uebertragung.info timestamp against the
|
||||
* staged copy of the last successfully imported export
|
||||
* (var/transient/ep_products_import/current/uebertragung.info) — not the
|
||||
* fileadmin/products_import.info marker, which is now display-only.
|
||||
*/
|
||||
final class SftpImportSource implements ProductImportSource, SingletonInterface, LoggerAwareInterface
|
||||
{
|
||||
use LoggerAwareTrait;
|
||||
|
||||
private const MARKER_FILE = 'uebertragung.info';
|
||||
private const PICKUPS_FILE = 'zustiege.xml';
|
||||
private const PRODUCT_PREFIX = 'Ziel';
|
||||
private const MARKER_TS_FORMAT = 'd.m.Y H:i:s';
|
||||
private const STAGING_SUBDIR = 'ep_products_import';
|
||||
private const PUBLISHED_DIR = 'current';
|
||||
|
||||
/** phpseclib rawlist() attribute value for a directory (NET_SFTP_TYPE_DIRECTORY). */
|
||||
private const REMOTE_TYPE_DIRECTORY = 2;
|
||||
|
||||
private const IMPORT_MARKER = 'fileadmin/products_import.info';
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
private $configuration;
|
||||
|
||||
/**
|
||||
* {@see ProductImportSource::acquire()} — {@see fetchIfNewer()}, read through
|
||||
* an {@see XmlProductReader}.
|
||||
*/
|
||||
public function acquire(): ?ProductImport
|
||||
{
|
||||
$path = $this->fetchIfNewer();
|
||||
if ($path === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$reader = new XmlProductReader($path, $this->logger);
|
||||
|
||||
return new ProductImport($reader, $reader->getSourceGeneratedAt(), $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@see ProductImportSource::markImported()} — publish the download as the new
|
||||
* change-detection baseline (only reached after a successful import), then
|
||||
* refresh the display-only marker for the BE module and system-info toolbar.
|
||||
*/
|
||||
public function markImported(ProductImport $import): void
|
||||
{
|
||||
$this->commit((string)$import->getLocation());
|
||||
(new ImportTimestampService())->writeImportTimestamp(self::IMPORT_MARKER);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@see ProductImportSource::isNewImportAvailable()} — alias for {@see isRemoteNewer()}.
|
||||
*/
|
||||
public function isNewImportAvailable(): bool
|
||||
{
|
||||
return $this->isRemoteNewer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Timestamp of the export currently offered on the remote server, or null when
|
||||
* the marker is absent/unreadable/unparseable (supplier upload not finished).
|
||||
*/
|
||||
public function getRemoteUploadTimestamp(): ?\DateTime
|
||||
{
|
||||
$config = $this->buildConfig();
|
||||
$sftp = $this->connect($config);
|
||||
try {
|
||||
[, $markerBytes] = $this->readRemoteMarker($sftp, $config['remotePath']);
|
||||
} finally {
|
||||
$sftp->disconnect();
|
||||
}
|
||||
|
||||
return $markerBytes !== null ? $this->parseMarkerTimestamp($markerBytes) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Timestamp of the export we last successfully imported (staged marker copy).
|
||||
*/
|
||||
public function getStagedImportedTimestamp(): ?\DateTime
|
||||
{
|
||||
$marker = $this->stagingBasePath() . '/' . self::PUBLISHED_DIR . '/' . self::MARKER_FILE;
|
||||
if (!is_file($marker)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->parseMarkerTimestamp((string)file_get_contents($marker));
|
||||
}
|
||||
|
||||
/**
|
||||
* True when the remote export is newer than the last imported one (or nothing
|
||||
* has been imported yet). False when there is nothing to do.
|
||||
*/
|
||||
public function isRemoteNewer(): bool
|
||||
{
|
||||
$remoteTs = $this->getRemoteUploadTimestamp();
|
||||
if ($remoteTs === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$stagedTs = $this->getStagedImportedTimestamp();
|
||||
|
||||
return $stagedTs === null || $remoteTs > $stagedTs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Freshness check + (only when newer) full download into a fresh temp dir.
|
||||
* Returns the temp-dir path — NOT yet published. The caller runs
|
||||
* DateImportService::import() against it and calls {@see commit()} on success.
|
||||
* Returns null when the remote export is not newer / not ready.
|
||||
*
|
||||
* @throws SftpImportException on connect/auth/host-key/partial-transfer failure
|
||||
*/
|
||||
public function fetchIfNewer(): ?string
|
||||
{
|
||||
$this->cleanupStale();
|
||||
$config = $this->buildConfig();
|
||||
$sftp = $this->connect($config);
|
||||
|
||||
try {
|
||||
[$remoteDir, $markerBytes] = $this->readRemoteMarker($sftp, $config['remotePath']);
|
||||
$remoteTs = $markerBytes !== null ? $this->parseMarkerTimestamp($markerBytes) : null;
|
||||
|
||||
if ($remoteTs === null) {
|
||||
$this->logWarning('remote upload marker missing or unparseable; skipping product import', [
|
||||
'host' => $config['host'],
|
||||
'remotePath' => $config['remotePath'],
|
||||
]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$stagedTs = $this->getStagedImportedTimestamp();
|
||||
if ($stagedTs !== null && $remoteTs <= $stagedTs) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->downloadInto($sftp, $remoteDir, $markerBytes);
|
||||
} finally {
|
||||
$sftp->disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unconditional download into a fresh temp dir. Returns the temp-dir path.
|
||||
*
|
||||
* @throws SftpImportException
|
||||
*/
|
||||
public function fetch(): string
|
||||
{
|
||||
$this->cleanupStale();
|
||||
$config = $this->buildConfig();
|
||||
$sftp = $this->connect($config);
|
||||
|
||||
try {
|
||||
[$remoteDir, $markerBytes] = $this->readRemoteMarker($sftp, $config['remotePath']);
|
||||
if ($markerBytes === null) {
|
||||
throw new SftpImportException(
|
||||
'Remote export has no readable ' . self::MARKER_FILE . ' under "' . $config['remotePath'] . '"'
|
||||
);
|
||||
}
|
||||
|
||||
return $this->downloadInto($sftp, $remoteDir, $markerBytes);
|
||||
} finally {
|
||||
$sftp->disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish a temp dir produced by {@see fetchIfNewer()} / {@see fetch()} to
|
||||
* .../current, making its marker the new change-detection baseline. Call only
|
||||
* after import() succeeded.
|
||||
*
|
||||
* @throws SftpImportException
|
||||
*/
|
||||
public function commit(string $stagedPath): string
|
||||
{
|
||||
$base = $this->stagingBasePath();
|
||||
$stagedPath = rtrim($stagedPath, '/');
|
||||
|
||||
if (strpos($stagedPath . '/', $base . '/') !== 0 || !is_dir($stagedPath)) {
|
||||
throw new SftpImportException('Refusing to publish unknown staging directory: ' . $stagedPath);
|
||||
}
|
||||
|
||||
$published = $base . '/' . self::PUBLISHED_DIR;
|
||||
|
||||
if (is_dir($published)) {
|
||||
$retired = $published . '.old-' . time() . '-' . bin2hex(random_bytes(3));
|
||||
if (!@rename($published, $retired)) {
|
||||
throw new SftpImportException('Cannot move previous import aside: ' . $published);
|
||||
}
|
||||
}
|
||||
|
||||
if (!@rename($stagedPath, $published)) {
|
||||
throw new SftpImportException('Cannot publish staging directory to ' . $published);
|
||||
}
|
||||
|
||||
foreach ((array)glob($base . '/' . self::PUBLISHED_DIR . '.old-*', GLOB_ONLYDIR) as $old) {
|
||||
GeneralUtility::rmdir($old, true);
|
||||
}
|
||||
|
||||
return $published;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{host:string,port:int,user:string,password:string,remotePath:string,timeout:int,hostKey:string} $config
|
||||
*/
|
||||
private function connect(array $config): SFTP
|
||||
{
|
||||
try {
|
||||
$sftp = new SFTP($config['host'], $config['port'], $config['timeout']);
|
||||
} catch (\Throwable $e) {
|
||||
throw new SftpImportException(
|
||||
sprintf('Cannot connect to SFTP host %s:%d: %s', $config['host'], $config['port'], $e->getMessage()),
|
||||
0,
|
||||
$e
|
||||
);
|
||||
}
|
||||
|
||||
if ($config['hostKey'] !== '') {
|
||||
$this->verifyHostKey($sftp, $config['host'], $config['hostKey']);
|
||||
}
|
||||
|
||||
try {
|
||||
$authenticated = $sftp->login($config['user'], $config['password']);
|
||||
} catch (\Throwable $e) {
|
||||
throw new SftpImportException(
|
||||
sprintf('Cannot connect to SFTP host %s:%d: %s', $config['host'], $config['port'], $e->getMessage()),
|
||||
0,
|
||||
$e
|
||||
);
|
||||
}
|
||||
|
||||
if ($authenticated !== true) {
|
||||
throw new SftpImportException(sprintf('SFTP authentication failed for user "%s"', $config['user']));
|
||||
}
|
||||
|
||||
return $sftp;
|
||||
}
|
||||
|
||||
private function verifyHostKey(SFTP $sftp, string $host, string $expected): void
|
||||
{
|
||||
try {
|
||||
$actual = $sftp->getServerPublicHostKey();
|
||||
} catch (\Throwable $e) {
|
||||
throw new SftpImportException('Cannot read SSH host key for ' . $host . ': ' . $e->getMessage(), 0, $e);
|
||||
}
|
||||
|
||||
if ($actual === false) {
|
||||
throw new SftpImportException('Cannot read SSH host key for ' . $host);
|
||||
}
|
||||
|
||||
$expected = trim($expected);
|
||||
$actual = trim($actual);
|
||||
|
||||
if (hash_equals($actual, $expected)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$parts = explode(' ', $actual);
|
||||
$rawKey = isset($parts[1]) ? base64_decode($parts[1], true) : false;
|
||||
if ($rawKey !== false) {
|
||||
$fingerprint = 'SHA256:' . rtrim(base64_encode(hash('sha256', $rawKey, true)), '=');
|
||||
if (hash_equals($fingerprint, $expected)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new SftpImportException('SSH host key mismatch for ' . $host . ' — refusing to connect');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the upload marker, probing each acceptable form of the configured
|
||||
* remote directory. Some SFTP servers (e.g. Hetzner Storage Box) only accept
|
||||
* paths relative to the login directory and silently fail on a leading slash.
|
||||
*
|
||||
* @return array{0:string,1:?string} the directory form that worked, and the marker bytes (null if none did)
|
||||
*/
|
||||
private function readRemoteMarker(SFTP $sftp, string $configuredPath): array
|
||||
{
|
||||
$candidates = $this->remoteDirCandidates($configuredPath);
|
||||
|
||||
foreach ($candidates as $dir) {
|
||||
try {
|
||||
$contents = $sftp->get($this->joinRemote($dir, self::MARKER_FILE));
|
||||
} catch (\Throwable $e) {
|
||||
throw new SftpImportException(
|
||||
'Failed to read remote ' . self::MARKER_FILE . ': ' . $e->getMessage(),
|
||||
0,
|
||||
$e
|
||||
);
|
||||
}
|
||||
|
||||
if ($contents !== false) {
|
||||
return [$dir, (string)$contents];
|
||||
}
|
||||
}
|
||||
|
||||
return [$candidates[0], null];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[] non-empty, unique
|
||||
*/
|
||||
private function remoteDirCandidates(string $configuredPath): array
|
||||
{
|
||||
$configured = trim($configuredPath);
|
||||
$relative = ltrim($configured, '/');
|
||||
|
||||
$candidates = [];
|
||||
if ($configured !== '' && $configured !== '/') {
|
||||
$candidates[] = $configured;
|
||||
}
|
||||
if ($relative !== '' && $relative !== $configured) {
|
||||
$candidates[] = $relative;
|
||||
}
|
||||
$candidates[] = '.';
|
||||
|
||||
return array_values(array_unique($candidates));
|
||||
}
|
||||
|
||||
/**
|
||||
* Download Ziel_*.xml + zustiege.xml + uebertragung.info into a fresh temp dir,
|
||||
* verifying each file's size against the remote listing. The marker is written
|
||||
* last, from the bytes already fetched for the freshness check.
|
||||
*
|
||||
* @throws SftpImportException
|
||||
*/
|
||||
private function downloadInto(SFTP $sftp, string $remotePath, string $markerBytes): string
|
||||
{
|
||||
$list = $sftp->rawlist($remotePath, false);
|
||||
if ($list === false) {
|
||||
throw new SftpImportException('Cannot list remote directory ' . $remotePath);
|
||||
}
|
||||
|
||||
$productFiles = [];
|
||||
$pickupSize = null;
|
||||
foreach ($list as $name => $attrs) {
|
||||
if ($name === '.' || $name === '..' || !is_array($attrs)) {
|
||||
continue;
|
||||
}
|
||||
if ((int)($attrs['type'] ?? 0) === self::REMOTE_TYPE_DIRECTORY) {
|
||||
continue;
|
||||
}
|
||||
if (strpos($name, self::PRODUCT_PREFIX) === 0 && substr($name, -4) === '.xml') {
|
||||
$productFiles[$name] = (int)($attrs['size'] ?? -1);
|
||||
} elseif ($name === self::PICKUPS_FILE) {
|
||||
$pickupSize = (int)($attrs['size'] ?? -1);
|
||||
}
|
||||
}
|
||||
|
||||
if (count($productFiles) === 0) {
|
||||
throw new SftpImportException('Remote export contains no ' . self::PRODUCT_PREFIX . '_*.xml files');
|
||||
}
|
||||
|
||||
$previousCount = $this->stagedProductFileCount();
|
||||
if ($previousCount > 0 && count($productFiles) < (int)floor($previousCount * 0.5)) {
|
||||
throw new SftpImportException(sprintf(
|
||||
'Remote export looks truncated (%d %s_*.xml files vs %d previously) — refusing to import',
|
||||
count($productFiles),
|
||||
self::PRODUCT_PREFIX,
|
||||
$previousCount
|
||||
));
|
||||
}
|
||||
|
||||
$toDownload = $productFiles;
|
||||
if ($pickupSize !== null) {
|
||||
$toDownload[self::PICKUPS_FILE] = $pickupSize;
|
||||
} else {
|
||||
$this->logWarning('remote export has no ' . self::PICKUPS_FILE . '; pickups will be skipped');
|
||||
}
|
||||
|
||||
$tmp = $this->newTempDir();
|
||||
|
||||
foreach ($toDownload as $name => $expectedSize) {
|
||||
$target = $tmp . '/' . $name;
|
||||
try {
|
||||
$ok = $sftp->get($this->joinRemote($remotePath, $name), $target);
|
||||
} catch (\Throwable $e) {
|
||||
GeneralUtility::rmdir($tmp, true);
|
||||
throw new SftpImportException('Download failed for ' . $name . ': ' . $e->getMessage(), 0, $e);
|
||||
}
|
||||
|
||||
if ($ok === false || !is_file($target)) {
|
||||
GeneralUtility::rmdir($tmp, true);
|
||||
throw new SftpImportException('Download failed for ' . $name);
|
||||
}
|
||||
|
||||
clearstatcache(true, $target);
|
||||
if ($expectedSize >= 0 && filesize($target) !== $expectedSize) {
|
||||
$actualSize = filesize($target);
|
||||
GeneralUtility::rmdir($tmp, true);
|
||||
throw new SftpImportException(sprintf(
|
||||
'Size mismatch for %s (got %d bytes, expected %d)',
|
||||
$name,
|
||||
$actualSize,
|
||||
$expectedSize
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Write the completion marker last, mirroring the supplier's upload order.
|
||||
GeneralUtility::writeFile($tmp . '/' . self::MARKER_FILE, $markerBytes, false);
|
||||
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
private function stagedProductFileCount(): int
|
||||
{
|
||||
$dir = $this->stagingBasePath() . '/' . self::PUBLISHED_DIR;
|
||||
if (!is_dir($dir)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
foreach ((array)scandir($dir) as $name) {
|
||||
if (strpos((string)$name, self::PRODUCT_PREFIX) === 0 && substr((string)$name, -4) === '.xml') {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
private function parseMarkerTimestamp(string $contents): ?\DateTime
|
||||
{
|
||||
$line = trim((string)strtok($contents, "\r\n"));
|
||||
if ($line === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$date = \DateTime::createFromFormat(self::MARKER_TS_FORMAT, $line);
|
||||
|
||||
return $date instanceof \DateTime ? $date : null;
|
||||
}
|
||||
|
||||
private function logWarning(string $message, array $context = []): void
|
||||
{
|
||||
if ($this->logger !== null) {
|
||||
$this->logger->warning($message, $context);
|
||||
}
|
||||
}
|
||||
|
||||
private function stagingBasePath(): string
|
||||
{
|
||||
return Environment::getVarPath() . '/transient/' . self::STAGING_SUBDIR;
|
||||
}
|
||||
|
||||
private function newTempDir(): string
|
||||
{
|
||||
$dir = $this->stagingBasePath() . '/.tmp-' . getmypid() . '-' . bin2hex(random_bytes(4));
|
||||
GeneralUtility::mkdir_deep($dir);
|
||||
if (!is_dir($dir) || !is_writable($dir)) {
|
||||
throw new SftpImportException('Cannot create staging directory: ' . $dir);
|
||||
}
|
||||
|
||||
return $dir;
|
||||
}
|
||||
|
||||
private function cleanupStale(): void
|
||||
{
|
||||
$base = $this->stagingBasePath();
|
||||
if (!is_dir($base)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$stale = array_merge(
|
||||
(array)glob($base . '/.tmp-*', GLOB_ONLYDIR),
|
||||
(array)glob($base . '/' . self::PUBLISHED_DIR . '.old-*', GLOB_ONLYDIR)
|
||||
);
|
||||
foreach ($stale as $dir) {
|
||||
GeneralUtility::rmdir($dir, true);
|
||||
}
|
||||
}
|
||||
|
||||
private function joinRemote(string $base, string $name): string
|
||||
{
|
||||
return rtrim($base, '/') . '/' . ltrim($name, '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{host:string,port:int,user:string,password:string,remotePath:string,timeout:int,hostKey:string}
|
||||
*/
|
||||
private function buildConfig(): array
|
||||
{
|
||||
if ($this->configuration === null) {
|
||||
$raw = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('ep_products');
|
||||
$raw = is_array($raw) ? $raw : [];
|
||||
|
||||
$host = trim((string)($raw['productImportSftpHost'] ?? ''));
|
||||
$user = trim((string)($raw['productImportSftpUser'] ?? ''));
|
||||
$password = (string)($raw['productImportSftpPassword'] ?? '');
|
||||
$remotePath = trim((string)($raw['productImportSftpRemotePath'] ?? '/'));
|
||||
$port = (int)($raw['productImportSftpPort'] ?? 22);
|
||||
$timeout = (int)($raw['productImportSftpTimeout'] ?? 15);
|
||||
$hostKey = trim((string)($raw['productImportSftpHostKey'] ?? ''));
|
||||
|
||||
if ($host === '' || $user === '') {
|
||||
throw new SftpImportException(
|
||||
'SFTP product import is not configured: host and username are required '
|
||||
. '(Admin Tools → Settings → Extension Configuration → ep_products).'
|
||||
);
|
||||
}
|
||||
if ($password === '') {
|
||||
throw new SftpImportException('SFTP product import is not configured: password is required.');
|
||||
}
|
||||
|
||||
$this->configuration = [
|
||||
'host' => $host,
|
||||
'port' => $port > 0 ? $port : 22,
|
||||
'user' => $user,
|
||||
'password' => $password,
|
||||
'remotePath' => $remotePath === '' ? '/' : $remotePath,
|
||||
'timeout' => $timeout > 0 ? $timeout : 15,
|
||||
'hostKey' => $hostKey,
|
||||
];
|
||||
}
|
||||
|
||||
return $this->configuration;
|
||||
}
|
||||
}
|
||||
@@ -1,621 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Service;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Domain\Model\Snowreport;
|
||||
use EP\EpProducts\Domain\Model\Webcam;
|
||||
use EP\EpProducts\Domain\Repository\RegionRepository;
|
||||
use EP\EpProducts\Domain\Repository\SnowreportRepository;
|
||||
use EP\EpProducts\Domain\Repository\WebcamRepository;
|
||||
use EP\EpProducts\Utility\SettingsUtility;
|
||||
use TYPO3\CMS\Core\Database\Connection;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
|
||||
use TYPO3\CMS\Core\Http\RequestFactory;
|
||||
use TYPO3\CMS\Core\SingletonInterface;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface;
|
||||
|
||||
class SnowreportImportService implements SingletonInterface
|
||||
{
|
||||
const XML_FILE_PATH = 'fileadmin/snowreport/snowreport.xml';
|
||||
const XML_FILE_URL = 'https://www.skiresort-service.com/xml-feed/';
|
||||
|
||||
/**
|
||||
* Connection and read timeout for the feed download, in seconds. A healthy response to this
|
||||
* endpoint arrives in well under a second, so the ceiling is kept low enough that an outage on
|
||||
* the vendor side fails visibly instead of stalling the scheduler task or the backend request.
|
||||
*/
|
||||
const HTTP_CONNECT_TIMEOUT = 5;
|
||||
const HTTP_TIMEOUT = 30;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $validSnowreportUids = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $validWebcamUids = [];
|
||||
|
||||
/**
|
||||
* Existing records keyed by vendor_uid, preloaded once per import to avoid a query per record.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $snowreportIndex = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $webcamIndex = [];
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager
|
||||
*/
|
||||
protected $persistenceManager;
|
||||
|
||||
/**
|
||||
* @var \EP\EpProducts\Domain\Repository\SnowreportRepository
|
||||
*/
|
||||
protected $snowreportRepository;
|
||||
|
||||
/**
|
||||
* @var \EP\EpProducts\Domain\Repository\WebcamRepository
|
||||
*/
|
||||
protected $webcamRepository;
|
||||
|
||||
/**
|
||||
* @var \EP\EpProducts\Domain\Repository\RegionRepository
|
||||
*/
|
||||
protected $regionRepository;
|
||||
|
||||
/**
|
||||
* @param PersistenceManagerInterface $persistenceManager
|
||||
* @param SnowreportRepository $snowreportRepository
|
||||
* @param WebcamRepository $webcamRepository
|
||||
* @param RegionRepository $regionRepository
|
||||
*/
|
||||
public function __construct(
|
||||
PersistenceManagerInterface $persistenceManager,
|
||||
SnowreportRepository $snowreportRepository,
|
||||
WebcamRepository $webcamRepository,
|
||||
RegionRepository $regionRepository
|
||||
) {
|
||||
$this->persistenceManager = $persistenceManager;
|
||||
$this->snowreportRepository = $snowreportRepository;
|
||||
$this->webcamRepository = $webcamRepository;
|
||||
$this->regionRepository = $regionRepository;
|
||||
}
|
||||
|
||||
const TYPE_INT = 'int';
|
||||
const TYPE_STRING = 'string';
|
||||
const TYPE_BOOL = 'bool';
|
||||
const TYPE_DATE = 'date';
|
||||
|
||||
/**
|
||||
* Declared schema of the vendor feed: XML element name => target column and its type.
|
||||
*
|
||||
* XML carries no type information - every element is a string - so the type of each field is
|
||||
* declared here rather than guessed from the value. Values are converted strictly according to
|
||||
* this table; anything unexpected is logged and falls back to the type's empty value instead of
|
||||
* silently changing type.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $map = [
|
||||
'region_id' => ['column' => 'vendor_uid', 'type' => self::TYPE_INT],
|
||||
'region_name' => ['column' => 'region_name', 'type' => self::TYPE_STRING],
|
||||
'region_offen' => ['column' => 'opened', 'type' => self::TYPE_BOOL],
|
||||
'gletschergebiet' => ['column' => 'glacier', 'type' => self::TYPE_BOOL],
|
||||
'schneehoehe_berg' => ['column' => 'snow_level_mountain', 'type' => self::TYPE_INT],
|
||||
'schneehoehe_tal' => ['column' => 'snow_level_valley', 'type' => self::TYPE_INT],
|
||||
'schneequalitaet' => ['column' => 'snow_quality', 'type' => self::TYPE_STRING],
|
||||
'letzter_schneefall' => ['column' => 'last_snowfall', 'type' => self::TYPE_DATE],
|
||||
'lifte_gesamt' => ['column' => 'lifts_total', 'type' => self::TYPE_INT],
|
||||
'offene_lifte' => ['column' => 'lifts_opened', 'type' => self::TYPE_INT],
|
||||
'letzte_aktualisierung' => ['column' => 'last_update', 'type' => self::TYPE_DATE],
|
||||
'hoehemax' => ['column' => 'height_max', 'type' => self::TYPE_INT],
|
||||
'hoehemin' => ['column' => 'height_min', 'type' => self::TYPE_INT],
|
||||
'datum_saisonstart' => ['column' => 'season_start', 'type' => self::TYPE_DATE],
|
||||
'datum_saisonende' => ['column' => 'season_end', 'type' => self::TYPE_DATE],
|
||||
];
|
||||
|
||||
/**
|
||||
* Accepted boolean representations, lowercased.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $booleanMap = [
|
||||
'true' => true,
|
||||
'1' => true,
|
||||
'ja' => true,
|
||||
'yes' => true,
|
||||
'false' => false,
|
||||
'0' => false,
|
||||
'nein' => false,
|
||||
'no' => false,
|
||||
];
|
||||
|
||||
/**
|
||||
* Distinct conversion problems encountered during the current import.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $conversionWarnings = [];
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function importSnowReportData()
|
||||
{
|
||||
$count = 0;
|
||||
$file = GeneralUtility::getFileAbsFileName(self::XML_FILE_PATH);
|
||||
|
||||
if (!is_file($file)) {
|
||||
$this->writelog(sprintf('Snowreport XML import failed: file "%s" does not exist.', $file));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
$xmlData = $this->parseReportsXml((string) file_get_contents($file));
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->writelog(sprintf('Snowreport XML import failed: %s', $e->getMessage()));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->resetImportState();
|
||||
$this->buildIndexes();
|
||||
|
||||
$snowReportStoragePid = $this->getStoragePid();
|
||||
|
||||
foreach ($xmlData->schneemeldung as $reportXml)
|
||||
{
|
||||
$vendorUid = (int) $reportXml->region_id;
|
||||
$snowreport = $this->getSnowreport($vendorUid);
|
||||
|
||||
$row = [];
|
||||
foreach (static::$map as $key => $field)
|
||||
{
|
||||
if (!isset($reportXml->{$key})) {
|
||||
$this->addConversionWarning(sprintf('Element <%s> missing in feed.', $key));
|
||||
$row[$field['column']] = $this->getEmptyValue($field['type']);
|
||||
continue;
|
||||
}
|
||||
|
||||
$row[$field['column']] = $this->convertValue((string) $reportXml->{$key}, $field['type'], $key);
|
||||
}
|
||||
|
||||
$snowreport->setPid($snowReportStoragePid);
|
||||
$snowreport->setVendorUid($vendorUid);
|
||||
$snowreport->setRegionName($row['region_name']);
|
||||
$snowreport->setOpened($row['opened']);
|
||||
$snowreport->setGlacier($row['glacier']);
|
||||
$snowreport->setSnowLevelMountain($row['snow_level_mountain']);
|
||||
$snowreport->setSnowLevelValley($row['snow_level_valley']);
|
||||
$snowreport->setSnowQuality($row['snow_quality']);
|
||||
$snowreport->setLastSnowfall($row['last_snowfall']);
|
||||
$snowreport->setLiftsTotal($row['lifts_total']);
|
||||
$snowreport->setLiftsOpened($row['lifts_opened']);
|
||||
$snowreport->setLastUpdate($row['last_update']);
|
||||
$snowreport->setHeightMax($row['height_max']);
|
||||
$snowreport->setHeightMin($row['height_min']);
|
||||
$snowreport->setSeasonStart($row['season_start']);
|
||||
$snowreport->setSeasonEnd($row['season_end']);
|
||||
|
||||
if ($reportXml->webcam) {
|
||||
$this->importWebcamData($reportXml->webcam, $snowreport);
|
||||
}
|
||||
|
||||
// New objects are already registered via add(); only managed ones need update().
|
||||
if (!$snowreport->_isNew()) {
|
||||
$this->snowreportRepository->update($snowreport);
|
||||
}
|
||||
|
||||
$this->validSnowreportUids[] = $vendorUid;
|
||||
|
||||
$count++;
|
||||
}
|
||||
|
||||
$this->persistenceManager->persistAll();
|
||||
|
||||
$this->cleanupData('tx_epproducts_domain_model_webcam', $this->validWebcamUids);
|
||||
$this->cleanupData('tx_epproducts_domain_model_snowreport', $this->validSnowreportUids);
|
||||
$this->updateWebcamCounters();
|
||||
|
||||
$this->logConversionWarnings();
|
||||
$this->writelog(sprintf('Snowreport XML import successful (%d records).', $count));
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \SimpleXMLElement $xml
|
||||
* @param Snowreport $snowreport
|
||||
*/
|
||||
public function importWebcamData(\SimpleXMLElement $xml, Snowreport $snowreport)
|
||||
{
|
||||
$snowReportStoragePid = $this->getStoragePid();
|
||||
foreach ($xml->children() as $item)
|
||||
{
|
||||
$include = $this->convertValue((string) $item->aktuell, self::TYPE_BOOL, 'aktuell');
|
||||
$available = $this->convertValue((string) $item->verf, self::TYPE_BOOL, 'verf');
|
||||
$vendorUid = (int) $item->uid;
|
||||
|
||||
$webcam = isset($this->webcamIndex[$vendorUid]) ? $this->webcamIndex[$vendorUid] : null;
|
||||
|
||||
// Skip cams that are neither current nor already known
|
||||
if (null === $webcam && false === $include) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add new cam if not in db yet
|
||||
if (null === $webcam) {
|
||||
$webcam = new Webcam();
|
||||
$webcam->setVendorUid($vendorUid);
|
||||
$webcam->setPid($snowReportStoragePid);
|
||||
$this->webcamRepository->add($webcam);
|
||||
$this->webcamIndex[$vendorUid] = $webcam;
|
||||
$snowreport->addWebcam($webcam);
|
||||
}
|
||||
|
||||
$webcam->setUrl((string) $item->url);
|
||||
$webcam->setName((string) $item->dt);
|
||||
$webcam->setAvailable($available && $include);
|
||||
|
||||
$this->validWebcamUids[] = $vendorUid;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flags records that are no longer contained in the feed as deleted.
|
||||
*
|
||||
* @param string $table
|
||||
* @param array $validUids
|
||||
* @return int Number of records flagged
|
||||
*/
|
||||
public function cleanupData($table, array $validUids)
|
||||
{
|
||||
/** @var ConnectionPool $connectionPool */
|
||||
$connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
|
||||
$qb = $connectionPool->getQueryBuilderForTable($table);
|
||||
// Hidden records are still managed by the import, only deleted ones are out of scope.
|
||||
$qb->getRestrictions()
|
||||
->removeAll()
|
||||
->add(GeneralUtility::makeInstance(DeletedRestriction::class))
|
||||
;
|
||||
$result = $qb
|
||||
->select('vendor_uid')
|
||||
->from($table)
|
||||
->execute()
|
||||
->fetchAllAssociative()
|
||||
;
|
||||
|
||||
$currentUids = array_map(function ($row) {
|
||||
return (int)$row['vendor_uid'];
|
||||
}, $result);
|
||||
|
||||
$obsoleteUids = array_values(array_diff($currentUids, $validUids));
|
||||
if (0 === count($obsoleteUids)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$qb = $connectionPool->getQueryBuilderForTable($table);
|
||||
|
||||
return (int) $qb
|
||||
->update($table)
|
||||
->set('deleted', 1)
|
||||
->set('tstamp', isset($GLOBALS['EXEC_TIME']) ? $GLOBALS['EXEC_TIME'] : time())
|
||||
->where(
|
||||
$qb->expr()->in(
|
||||
'vendor_uid',
|
||||
$qb->createNamedParameter($obsoleteUids, Connection::PARAM_INT_ARRAY)
|
||||
)
|
||||
)
|
||||
->execute()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalculates the inline child counter on the snowreport records. Webcams are flagged as deleted
|
||||
* with plain SQL, which bypasses the counter Extbase maintains for the relation.
|
||||
*/
|
||||
protected function updateWebcamCounters()
|
||||
{
|
||||
$connection = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getConnectionForTable('tx_epproducts_domain_model_snowreport');
|
||||
|
||||
$connection->executeStatement(
|
||||
'UPDATE tx_epproducts_domain_model_snowreport s SET s.webcams = ('
|
||||
. ' SELECT COUNT(*) FROM tx_epproducts_domain_model_webcam w'
|
||||
. ' WHERE w.snowreport = s.uid AND w.deleted = 0'
|
||||
. ')'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the feed and replaces the local file only if the response is a usable XML document.
|
||||
* The existing file is left untouched on any failure.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function downloadReportsXml()
|
||||
{
|
||||
$path = GeneralUtility::getFileAbsFileName(self::XML_FILE_PATH);
|
||||
|
||||
try {
|
||||
$xmlContent = $this->fetchReportsXml();
|
||||
$this->parseReportsXml($xmlContent);
|
||||
} catch (\Exception $e) {
|
||||
$this->writelog(sprintf(
|
||||
'Snowreport XML download failed (%s). Keeping existing file.',
|
||||
$e->getMessage()
|
||||
));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write to a temporary file first and move it into place, so the feed is either the old or the
|
||||
// new document, never a partially written one.
|
||||
$temporaryPath = $path . '.tmp';
|
||||
if (false === file_put_contents($temporaryPath, $xmlContent) || !rename($temporaryPath, $path)) {
|
||||
@unlink($temporaryPath);
|
||||
$this->writelog(sprintf('Snowreport XML could not be written to "%s".', $path));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function fetchReportsXml()
|
||||
{
|
||||
/** @var RequestFactory $requestFactory */
|
||||
$requestFactory = GeneralUtility::makeInstance(RequestFactory::class);
|
||||
|
||||
$response = $requestFactory->request(self::XML_FILE_URL, 'GET', [
|
||||
'connect_timeout' => self::HTTP_CONNECT_TIMEOUT,
|
||||
'timeout' => self::HTTP_TIMEOUT,
|
||||
'headers' => [
|
||||
'Accept' => 'application/xml, text/xml',
|
||||
],
|
||||
]);
|
||||
|
||||
if (200 !== $response->getStatusCode()) {
|
||||
throw new \RuntimeException(
|
||||
sprintf('unexpected status code %d', $response->getStatusCode()),
|
||||
1758000001
|
||||
);
|
||||
}
|
||||
|
||||
return (string) $response->getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the feed and rejects documents that are unusable. Without this an empty or truncated
|
||||
* response would be imported as an empty feed, and the cleanup would flag every record as deleted.
|
||||
*
|
||||
* @param string $xmlContent
|
||||
* @return \SimpleXMLElement
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function parseReportsXml($xmlContent)
|
||||
{
|
||||
if ('' === trim($xmlContent)) {
|
||||
throw new \RuntimeException('response is empty', 1758000002);
|
||||
}
|
||||
|
||||
$useInternalErrors = libxml_use_internal_errors(true);
|
||||
libxml_clear_errors();
|
||||
$xmlData = simplexml_load_string($xmlContent);
|
||||
$errors = libxml_get_errors();
|
||||
libxml_clear_errors();
|
||||
libxml_use_internal_errors($useInternalErrors);
|
||||
|
||||
if (false === $xmlData) {
|
||||
$message = count($errors) > 0 ? trim($errors[0]->message) : 'unknown error';
|
||||
throw new \RuntimeException(sprintf('response is not valid XML (%s)', $message), 1758000003);
|
||||
}
|
||||
|
||||
if (0 === $xmlData->schneemeldung->count()) {
|
||||
throw new \RuntimeException('response contains no <schneemeldung> elements', 1758000004);
|
||||
}
|
||||
|
||||
return $xmlData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads existing records once, keyed by vendor_uid. Replaces a repository lookup per feed record.
|
||||
*/
|
||||
protected function buildIndexes()
|
||||
{
|
||||
$this->snowreportIndex = [];
|
||||
foreach ($this->snowreportRepository->findAll() as $snowreport) {
|
||||
$this->snowreportIndex[(int) $snowreport->getVendorUid()] = $snowreport;
|
||||
}
|
||||
|
||||
$this->webcamIndex = [];
|
||||
foreach ($this->webcamRepository->findAll() as $webcam) {
|
||||
$this->webcamIndex[(int) $webcam->getVendorUid()] = $webcam;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $vendorUid
|
||||
* @return Snowreport
|
||||
*/
|
||||
protected function getSnowreport($vendorUid)
|
||||
{
|
||||
if (isset($this->snowreportIndex[$vendorUid])) {
|
||||
return $this->snowreportIndex[$vendorUid];
|
||||
}
|
||||
|
||||
$snowreport = new Snowreport();
|
||||
$snowreport->setVendorUid($vendorUid);
|
||||
$this->snowreportRepository->add($snowreport);
|
||||
$this->snowreportIndex[$vendorUid] = $snowreport;
|
||||
|
||||
return $snowreport;
|
||||
}
|
||||
|
||||
/**
|
||||
* The service is a singleton, so per-import state must not survive into the next run.
|
||||
*/
|
||||
protected function resetImportState()
|
||||
{
|
||||
$this->validSnowreportUids = [];
|
||||
$this->validWebcamUids = [];
|
||||
$this->conversionWarnings = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a raw XML string to the declared type of the field.
|
||||
*
|
||||
* @param string $raw
|
||||
* @param string $type
|
||||
* @param string $key XML element name, for logging
|
||||
* @return int|string|bool
|
||||
*/
|
||||
protected function convertValue($raw, $type, $key)
|
||||
{
|
||||
$raw = trim($raw);
|
||||
|
||||
// The feed delivers empty elements for data that is not available yet (snow levels out of
|
||||
// season, for example). That is expected, not an error.
|
||||
if ($raw === '') {
|
||||
return $this->getEmptyValue($type);
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case self::TYPE_STRING:
|
||||
return $raw;
|
||||
|
||||
case self::TYPE_INT:
|
||||
if (!preg_match('/^-?\d+$/', $raw)) {
|
||||
$this->addConversionWarning(sprintf('<%s> expected an integer, got "%s".', $key, $raw));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int) $raw;
|
||||
|
||||
case self::TYPE_BOOL:
|
||||
$normalized = strtolower($raw);
|
||||
if (!array_key_exists($normalized, static::$booleanMap)) {
|
||||
$this->addConversionWarning(sprintf('<%s> expected a boolean, got "%s".', $key, $raw));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return static::$booleanMap[$normalized];
|
||||
|
||||
case self::TYPE_DATE:
|
||||
if (!preg_match('/^\d{4}-\d{2}-\d{2}([ T]\d{2}:\d{2}(:\d{2})?)?$/', $raw)) {
|
||||
$this->addConversionWarning(sprintf('<%s> expected a date, got "%s".', $key, $raw));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$date = new \DateTime($raw);
|
||||
|
||||
return $date->getTimestamp();
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf('Unknown field type "%s" declared for <%s>.', $type, $key), 1758000000);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @return int|string|bool
|
||||
*/
|
||||
protected function getEmptyValue($type)
|
||||
{
|
||||
if ($type === self::TYPE_STRING) {
|
||||
return '';
|
||||
}
|
||||
if ($type === self::TYPE_BOOL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
*/
|
||||
protected function addConversionWarning($message)
|
||||
{
|
||||
// Keyed to keep one entry per distinct problem instead of one per record.
|
||||
$this->conversionWarnings[$message] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a single summary entry to the log if the feed contained unexpected values.
|
||||
*/
|
||||
protected function logConversionWarnings()
|
||||
{
|
||||
if (0 === count($this->conversionWarnings)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$messages = array_keys($this->conversionWarnings);
|
||||
$this->writelog(sprintf(
|
||||
'Snowreport XML import: %d unexpected value(s) in feed: %s',
|
||||
count($messages),
|
||||
implode(' | ', array_slice($messages, 0, 10))
|
||||
));
|
||||
|
||||
$this->conversionWarnings = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* The scheduler task and the backend module provide a backend user, the CLI command does not.
|
||||
*
|
||||
* @param string $message
|
||||
*/
|
||||
protected function writelog($message)
|
||||
{
|
||||
if (isset($GLOBALS['BE_USER']) && is_object($GLOBALS['BE_USER'])) {
|
||||
$GLOBALS['BE_USER']->writelog(4, 0, 0, 0, $message, []);
|
||||
}
|
||||
}
|
||||
|
||||
public function getStoragePid()
|
||||
{
|
||||
$settingsUtility = new SettingsUtility();
|
||||
|
||||
return $settingsUtility->get('snowReportStoragePid');
|
||||
}
|
||||
}
|
||||
@@ -1,369 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Service;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\NullLogger;
|
||||
|
||||
/**
|
||||
* Reads a BusPro XML export directory (Ziel_*.xml, zustiege.xml) and yields one
|
||||
* row per travel date × hotel, in exactly the shape of the rows served by
|
||||
* GET /api/exports/products on MyE&P, so {@see DateImportService::import()}
|
||||
* does not care which of the two it is fed.
|
||||
*
|
||||
* Nothing is filtered or rewritten here: every display rule stays in
|
||||
* DateImportService. Prices are parsed from the German format, and a price the
|
||||
* source does not state is null. Like the API, service labels and pickup
|
||||
* cities and streets are trimmed with inner whitespace collapsed; every other
|
||||
* text is passed on verbatim.
|
||||
*/
|
||||
final class XmlProductReader implements \IteratorAggregate
|
||||
{
|
||||
private const PRODUCT_PREFIX = 'Ziel';
|
||||
private const PICKUPS_FILE = 'zustiege.xml';
|
||||
private const MARKER_FILE = 'uebertragung.info';
|
||||
private const MARKER_TS_FORMAT = 'd.m.Y H:i:s';
|
||||
private const CODE_PSEUDOPRICE = 'PDGS';
|
||||
private const TIMEZONE = 'Europe/Berlin';
|
||||
private const LOCAL_DATETIME_FORMAT = 'Y-m-d\TH:i:s';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $path;
|
||||
|
||||
/**
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* @var \DateTimeZone
|
||||
*/
|
||||
private $timezone;
|
||||
|
||||
/**
|
||||
* Pickup times are clock readings, not instants. They are handled in UTC,
|
||||
* which has no daylight saving gaps, so a time BusPro plans inside one
|
||||
* (02:45 on the night clocks go forward) is kept as stated.
|
||||
*
|
||||
* @var \DateTimeZone
|
||||
*/
|
||||
private $wallClock;
|
||||
|
||||
/**
|
||||
* @var array|null pickup master data by BusPro id
|
||||
*/
|
||||
private $pickups;
|
||||
|
||||
public function __construct(string $path, ?LoggerInterface $logger = null)
|
||||
{
|
||||
$this->path = rtrim($path, '/');
|
||||
$this->logger = $logger ?? new NullLogger();
|
||||
$this->timezone = new \DateTimeZone(self::TIMEZONE);
|
||||
$this->wallClock = new \DateTimeZone('UTC');
|
||||
}
|
||||
|
||||
public function getPath(): string
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* The export's own timestamp from uebertragung.info, or null if unreadable.
|
||||
*/
|
||||
public function getSourceGeneratedAt(): ?\DateTimeImmutable
|
||||
{
|
||||
$file = $this->path . '/' . self::MARKER_FILE;
|
||||
if (!is_file($file)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$line = trim((string) strtok((string) file_get_contents($file), "\r\n"));
|
||||
$date = \DateTimeImmutable::createFromFormat(self::MARKER_TS_FORMAT, $line, $this->timezone);
|
||||
|
||||
return $date ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Generator<array>
|
||||
*/
|
||||
public function getIterator(): \Generator
|
||||
{
|
||||
if ($this->pickups === null) {
|
||||
$this->pickups = $this->readPickups();
|
||||
}
|
||||
|
||||
$folder = opendir($this->path);
|
||||
if ($folder === false) {
|
||||
$this->logger->error('product xml directory not readable', ['path' => $this->path]);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
while (($fileName = readdir($folder)) !== false) {
|
||||
if (strpos($fileName, self::PRODUCT_PREFIX) === 0) {
|
||||
yield from $this->readProductFile($this->path . '/' . $fileName);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
closedir($folder);
|
||||
}
|
||||
}
|
||||
|
||||
private function readProductFile(string $file): \Generator
|
||||
{
|
||||
libxml_use_internal_errors(true);
|
||||
$xmlData = simplexml_load_string((string) file_get_contents($file));
|
||||
if ($xmlData === false) {
|
||||
libxml_clear_errors();
|
||||
$this->logger->error('product xml invalid', ['file' => $file]);
|
||||
return;
|
||||
}
|
||||
|
||||
$xmlProduct = $xmlData->reise[0];
|
||||
if ($xmlProduct === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$product = [
|
||||
'code' => (string) $xmlProduct['code'],
|
||||
'busProId' => (int) $xmlProduct['idbuspro'],
|
||||
];
|
||||
|
||||
foreach ($xmlProduct->termin as $xmlDate) {
|
||||
$from = $this->parseDate((string) $xmlDate['termin']);
|
||||
$to = $this->parseDate((string) $xmlDate['bis']);
|
||||
if ($from === null || $to === null) {
|
||||
$this->logger->warning('travel date skipped, dates unparseable', [
|
||||
'code' => (string) $xmlDate['code'],
|
||||
'termin' => (string) $xmlDate['termin'],
|
||||
'bis' => (string) $xmlDate['bis'],
|
||||
]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$date = [
|
||||
'code' => (string) $xmlDate['code'],
|
||||
'busProId' => (int) $xmlDate['idbuspro'],
|
||||
'from' => $from->format('Y-m-d'),
|
||||
'to' => $to->format('Y-m-d'),
|
||||
'type' => (string) $xmlDate['reiseart'],
|
||||
];
|
||||
|
||||
// Everything below is per travel date and shared by its hotels.
|
||||
$selectionGroups = $this->readSelectionGroups($xmlDate);
|
||||
$transportServices = $this->readServices($xmlDate, 'lei_befoerderung');
|
||||
$dateServices = $this->readServices($xmlDate, 'lei_sonstiges');
|
||||
$pickups = $this->readDatePickups($xmlDate, $from);
|
||||
$guide = $this->readGuide($xmlDate);
|
||||
|
||||
foreach ($xmlDate->hotel as $xmlHotel) {
|
||||
[$pseudoPrice, $rooms] = $this->readRooms($xmlHotel);
|
||||
|
||||
yield [
|
||||
'product' => $product,
|
||||
'date' => $date,
|
||||
'hotel' => [
|
||||
'code' => (string) $xmlHotel['code'],
|
||||
'busProId' => (int) $xmlHotel['idbuspro'],
|
||||
],
|
||||
'pseudoPrice' => $pseudoPrice,
|
||||
'selectionGroups' => $selectionGroups,
|
||||
'transportServices' => $transportServices,
|
||||
'dateServices' => $dateServices,
|
||||
'hotelServices' => $this->readServices($xmlHotel, 'lei_sonstiges'),
|
||||
'rooms' => $rooms,
|
||||
'pickups' => $pickups,
|
||||
'guide' => $guide,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function readSelectionGroups(\SimpleXMLElement $xmlDate): array
|
||||
{
|
||||
$groups = [];
|
||||
foreach ($xmlDate->selektiongruppe as $xmlGroup) {
|
||||
$selections = [];
|
||||
foreach ($xmlGroup->selektion as $xmlSelection) {
|
||||
$selections[] = [
|
||||
'busProId' => (int) $xmlSelection['idbuspro'],
|
||||
'label' => (string) $xmlSelection['bezeichnung'],
|
||||
];
|
||||
}
|
||||
$groups[] = [
|
||||
'busProId' => (int) $xmlGroup['idbuspro'],
|
||||
'label' => (string) $xmlGroup['bezeichnung'],
|
||||
'selections' => $selections,
|
||||
];
|
||||
}
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
||||
private function readServices(\SimpleXMLElement $xmlParent, string $list): array
|
||||
{
|
||||
$services = [];
|
||||
foreach ($xmlParent->xpath($list . '/leistung') as $xmlService) {
|
||||
$direction = trim((string) $xmlService->richtung);
|
||||
$services[] = [
|
||||
'busProId' => (int) $xmlService['idbuspro'],
|
||||
'subType' => (string) $xmlService['unterart'],
|
||||
'label' => $this->normalizeWhitespace((string) $xmlService->text),
|
||||
'price' => $this->parsePrice((string) $xmlService->preis),
|
||||
'status' => (string) $xmlService->status,
|
||||
'direction' => $direction === '' ? null : $direction,
|
||||
];
|
||||
}
|
||||
|
||||
return $services;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0: ?float, 1: array}
|
||||
*/
|
||||
private function readRooms(\SimpleXMLElement $xmlHotel): array
|
||||
{
|
||||
$pseudoPrice = null;
|
||||
$rooms = [];
|
||||
foreach ($xmlHotel->xpath('zimmer/preis') as $xmlRoom) {
|
||||
$code = trim((string) $xmlRoom['zimmercode']);
|
||||
if ($code === self::CODE_PSEUDOPRICE) {
|
||||
$pseudoPrice = $this->parsePrice((string) $xmlRoom['preis']);
|
||||
continue;
|
||||
}
|
||||
|
||||
$rooms[] = [
|
||||
'busProId' => (int) $xmlRoom['idbuspro_zimmer'],
|
||||
'code' => $code,
|
||||
'label' => (string) $xmlRoom['zimmertext'],
|
||||
'category' => (string) $xmlRoom['kat'],
|
||||
'minPax' => $this->parseInt((string) $xmlRoom['MinPax']),
|
||||
'maxPax' => $this->parseInt((string) $xmlRoom['MaxPax']),
|
||||
'nights' => $this->parseInt((string) $xmlRoom['naechte']),
|
||||
'price' => $this->parsePrice((string) $xmlRoom['preis']),
|
||||
'available' => $this->parseInt((string) $xmlRoom['verfuegbar']),
|
||||
'status' => (string) $xmlRoom['status'],
|
||||
'boardCode' => (string) $xmlRoom['vpcode'],
|
||||
'boardBusProId' => $this->parseInt((string) $xmlRoom['idbuspro_vp']),
|
||||
];
|
||||
}
|
||||
|
||||
return [$pseudoPrice, $rooms];
|
||||
}
|
||||
|
||||
/**
|
||||
* A bare HH:mm takes the travel date's start, and is rolled onto the next
|
||||
* day when it would otherwise fall before the latest full date-time listed
|
||||
* before it: a coach does not board backwards. The result is the local
|
||||
* date and time as BusPro states it, without an offset.
|
||||
*/
|
||||
private function readDatePickups(\SimpleXMLElement $xmlDate, \DateTimeImmutable $from): array
|
||||
{
|
||||
$pickups = [];
|
||||
$latest = null;
|
||||
foreach ($xmlDate->xpath('zustiege/zustieg') as $xmlPickup) {
|
||||
$busProId = (int) $xmlPickup['idbuspro'];
|
||||
$time = trim((string) $xmlPickup['zeit']);
|
||||
|
||||
$datetime = null;
|
||||
if ($time !== '' && strpos($time, ' ') !== false) {
|
||||
$datetime = \DateTimeImmutable::createFromFormat('!d.m.Y H:i:s', $time, $this->wallClock) ?: null;
|
||||
if ($datetime !== null && ($latest === null || $datetime > $latest)) {
|
||||
$latest = $datetime;
|
||||
}
|
||||
} elseif ($time !== '') {
|
||||
$datetime = \DateTimeImmutable::createFromFormat('!Y-m-d H:i', $from->format('Y-m-d') . ' ' . $time, $this->wallClock) ?: null;
|
||||
if ($datetime !== null && $latest !== null && $datetime < $latest) {
|
||||
$datetime = $datetime->modify('+1 day');
|
||||
}
|
||||
}
|
||||
|
||||
$masterData = $this->pickups[$busProId] ?? null;
|
||||
$pickups[] = [
|
||||
'busProId' => $busProId,
|
||||
'code' => $masterData['code'] ?? null,
|
||||
'city' => $masterData['city'] ?? null,
|
||||
'street' => $masterData['street'] ?? null,
|
||||
'price' => $this->parsePrice((string) $xmlPickup['preis']),
|
||||
'datetime' => $datetime !== null ? $datetime->format(self::LOCAL_DATETIME_FORMAT) : null,
|
||||
];
|
||||
}
|
||||
|
||||
return $pickups;
|
||||
}
|
||||
|
||||
private function readGuide(\SimpleXMLElement $xmlDate): ?array
|
||||
{
|
||||
foreach ($xmlDate->xpath('lei_befoerderung/leistung[@unterart="BUS"]') as $xmlService) {
|
||||
if ((string) $xmlService->richtung === 'RUECK') {
|
||||
continue;
|
||||
}
|
||||
if (!isset($xmlService->zustiegsplanung->reiseleiter)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return [
|
||||
'name' => (string) $xmlService->zustiegsplanung->reiseleiter->name,
|
||||
'phone' => (string) $xmlService->zustiegsplanung->reiseleiter->telefon,
|
||||
];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array{code: string, city: string, street: string}>
|
||||
*/
|
||||
private function readPickups(): array
|
||||
{
|
||||
$file = $this->path . '/' . self::PICKUPS_FILE;
|
||||
libxml_use_internal_errors(true);
|
||||
if (!is_file($file) || !$xmlData = simplexml_load_string((string) file_get_contents($file))) {
|
||||
libxml_clear_errors();
|
||||
$this->logger->warning('pickup xml missing or invalid', ['file' => $file]);
|
||||
return [];
|
||||
}
|
||||
|
||||
$pickups = [];
|
||||
foreach ($xmlData->zustieg as $xmlPickup) {
|
||||
$pickups[(int) $xmlPickup['idbuspro']] = [
|
||||
'code' => (string) $xmlPickup['code'],
|
||||
'city' => $this->normalizeWhitespace((string) $xmlPickup->ort),
|
||||
'street' => $this->normalizeWhitespace((string) $xmlPickup->strasse),
|
||||
];
|
||||
}
|
||||
|
||||
return $pickups;
|
||||
}
|
||||
|
||||
private function normalizeWhitespace(string $value): string
|
||||
{
|
||||
return trim((string) preg_replace('/\s+/u', ' ', $value));
|
||||
}
|
||||
|
||||
private function parseDate(string $value): ?\DateTimeImmutable
|
||||
{
|
||||
$date = \DateTimeImmutable::createFromFormat('!d.m.Y', trim($value), $this->timezone);
|
||||
|
||||
return $date ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* German format with an optional thousands separator: "1.234,50" is 1234.5.
|
||||
*/
|
||||
private function parsePrice(string $value): ?float
|
||||
{
|
||||
$value = str_replace(['.', ','], ['', '.'], trim($value));
|
||||
|
||||
return is_numeric($value) ? (float) $value : null;
|
||||
}
|
||||
|
||||
private function parseInt(string $value): ?int
|
||||
{
|
||||
$value = trim($value);
|
||||
|
||||
return is_numeric($value) ? (int) $value : null;
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Task;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Service\ContingentImportService;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Object\ObjectManager;
|
||||
use TYPO3\CMS\Scheduler\Task\AbstractTask;
|
||||
|
||||
class ImportContingentsTask extends AbstractTask
|
||||
{
|
||||
public function execute()
|
||||
{
|
||||
/** @var \TYPO3\CMS\Extbase\Object\ObjectManager $objectManager */
|
||||
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
|
||||
/** @var \EP\EpProducts\Service\ContingentImportService $importService */
|
||||
$importService = $objectManager->get(ContingentImportService::class);
|
||||
if ($importService->isImportRequired()) {
|
||||
$importService->import();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Task;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Service\DateImportService;
|
||||
use EP\EpProducts\Service\ProductImportSourceFactory;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Configuration\ConfigurationManager;
|
||||
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
|
||||
use TYPO3\CMS\Extbase\Service\CacheService;
|
||||
use TYPO3\CMS\Scheduler\Task\AbstractTask;
|
||||
|
||||
class ImportDatesTask extends AbstractTask
|
||||
{
|
||||
public function execute(): bool
|
||||
{
|
||||
$importService = GeneralUtility::makeInstance(DateImportService::class);
|
||||
$importSource = GeneralUtility::makeInstance(ProductImportSourceFactory::class)->get();
|
||||
$cacheService = GeneralUtility::makeInstance(CacheService::class);
|
||||
|
||||
// Acquire the export only when it is newer than the one we last imported
|
||||
// (SFTP mode: download to a staging dir; local mode: fileadmin/xmlexport;
|
||||
// API mode: walk the MyE&P export pages). An acquisition failure is left
|
||||
// to propagate so the scheduler marks the task failed.
|
||||
$import = $importSource->acquire();
|
||||
|
||||
if ($import !== null) {
|
||||
$importService->import($import->getRows());
|
||||
// Advance the "last imported" bookkeeping only after a successful
|
||||
// import, so a crashed import retries on the next run.
|
||||
$importSource->markImported($import);
|
||||
}
|
||||
|
||||
$settings = $this->getSettings();
|
||||
$travelInfoPageUid = $settings['travelInfoPageUid'];
|
||||
$cacheService->clearPageCache($travelInfoPageUid);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getSettings(): array
|
||||
{
|
||||
$configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class);
|
||||
$settings = $configurationManager
|
||||
->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT);
|
||||
|
||||
return $settings['plugin.']['tx_epproducts.']['settings.'];
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Task;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* 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\Service\SnowreportImportService;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Object\ObjectManager;
|
||||
use TYPO3\CMS\Scheduler\Task\AbstractTask;
|
||||
|
||||
class ImportSnowreportTask extends AbstractTask
|
||||
{
|
||||
public function execute()
|
||||
{
|
||||
/** @var \TYPO3\CMS\Extbase\Object\ObjectManager $objectManager */
|
||||
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
|
||||
$snowreportService = $objectManager->get(SnowreportImportService::class);
|
||||
$snowreportService->downloadReportsXml();
|
||||
$snowreportService->importSnowReportData();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Updates;
|
||||
|
||||
use GeorgRinger\News\Service\Transliterator\Transliterator;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Install\Updates\DatabaseUpdatedPrerequisite;
|
||||
use TYPO3\CMS\Install\Updates\UpgradeWizardInterface;
|
||||
|
||||
class TeamSlugUpdater implements UpgradeWizardInterface
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Updates slug field "path_segment" of EXT:ep_products team records';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Fills empty slug field "path_segment" of EXT:ep_products records with urlized name.';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return 'teamSlug';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function updateNecessary(): bool
|
||||
{
|
||||
$elementCount = $this->countRequiredUpdates();
|
||||
|
||||
return (bool)$elementCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function executeUpdate(): bool
|
||||
{
|
||||
$queryBuilder = $this->getQueryBuilder();
|
||||
|
||||
$statement = $queryBuilder->select('uid', 'name')
|
||||
->from('tx_epproducts_domain_model_teammember')
|
||||
->where(
|
||||
$queryBuilder->expr()->orX(
|
||||
$queryBuilder->expr()->eq(
|
||||
'path_segment',
|
||||
$queryBuilder->createNamedParameter('')
|
||||
),
|
||||
$queryBuilder->expr()->isNull('path_segment')
|
||||
)
|
||||
)
|
||||
->execute();
|
||||
while ($record = $statement->fetch()) {
|
||||
$slug = Transliterator::urlize($record['name']);
|
||||
$queryBuilder = $this->getQueryBuilder();
|
||||
$queryBuilder->update('tx_epproducts_domain_model_teammember')
|
||||
->where(
|
||||
$queryBuilder->expr()->eq(
|
||||
'uid',
|
||||
$queryBuilder->createNamedParameter($record['uid'], \PDO::PARAM_INT)
|
||||
)
|
||||
)
|
||||
->set('path_segment', $slug);
|
||||
$queryBuilder->execute();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function countRequiredUpdates(): int
|
||||
{
|
||||
$queryBuilder = $this->getQueryBuilder();
|
||||
|
||||
return $queryBuilder->count('uid')
|
||||
->from('tx_epproducts_domain_model_teammember')
|
||||
->where(
|
||||
$queryBuilder->expr()->orX(
|
||||
$queryBuilder->expr()->eq(
|
||||
'path_segment',
|
||||
$queryBuilder->createNamedParameter('')
|
||||
),
|
||||
$queryBuilder->expr()->isNull('path_segment')
|
||||
)
|
||||
)
|
||||
->execute()->fetchColumn();
|
||||
}
|
||||
|
||||
protected function getQueryBuilder(): QueryBuilder
|
||||
{
|
||||
/** @var QueryBuilder $queryBuilder */
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getQueryBuilderForTable('tx_epproducts_domain_model_teammember');
|
||||
$queryBuilder->getRestrictions()->removeAll();
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getPrerequisites(): array
|
||||
{
|
||||
return [
|
||||
DatabaseUpdatedPrerequisite::class,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,7 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'ep:export' => [
|
||||
'class' => \EP\EpProducts\Command\ExportCommandController::class,
|
||||
'scheduleable' => false,
|
||||
],
|
||||
'ep:groups-swiss' => [
|
||||
'class' => \EP\EpProducts\Command\GroupsSwissCommand::class,
|
||||
],
|
||||
'ep:contingent-import' => [
|
||||
'class' => \EP\EpProducts\Command\ContingentCommand::class,
|
||||
'scheduleable' => false,
|
||||
'ep:import-dates' => [
|
||||
'class' => \EP\EpProducts\Command\DateCommandController::class,
|
||||
],
|
||||
];
|
||||
@@ -1,40 +0,0 @@
|
||||
<T3DataStructure>
|
||||
<meta>
|
||||
<langDisable>1</langDisable>
|
||||
</meta>
|
||||
<sheets>
|
||||
<sDEF>
|
||||
<ROOT>
|
||||
<TCEforms>
|
||||
<sheetTitle>Konfiguration</sheetTitle>
|
||||
</TCEforms>
|
||||
<type>array</type>
|
||||
<el>
|
||||
<settings.cityUid>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Ort</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_city</foreign_table>
|
||||
<foreign_table_where>AND tx_epproducts_domain_model_city.hidden = 0 AND tx_epproducts_domain_model_city.deleted = 0 ORDER BY tx_epproducts_domain_model_city.name</foreign_table_where>
|
||||
<minitems>1</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.cityUid>
|
||||
<settings.hideMoreLink>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Link zum Suchergebnis ausblenden:</label>
|
||||
<config>
|
||||
<type>check</type>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.hideMoreLink>
|
||||
</el>
|
||||
</ROOT>
|
||||
</sDEF>
|
||||
</sheets>
|
||||
</T3DataStructure>
|
||||
@@ -1,79 +0,0 @@
|
||||
<T3DataStructure>
|
||||
<meta>
|
||||
<langDisable>1</langDisable>
|
||||
</meta>
|
||||
<sheets>
|
||||
<sDEF>
|
||||
<ROOT>
|
||||
<TCEforms>
|
||||
<sheetTitle>Konfiguration</sheetTitle>
|
||||
</TCEforms>
|
||||
<type>array</type>
|
||||
<el>
|
||||
<settings.countryUid>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Land</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_country</foreign_table>
|
||||
<foreign_table_where>ORDER BY name</foreign_table_where>
|
||||
<items type="array">
|
||||
<numIndex index="0" type="array">
|
||||
<numIndex index="0"></numIndex>
|
||||
<numIndex index="1">0</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
<minitems>0</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.countryUid>
|
||||
<settings.regionUid>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Gebiet</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_region</foreign_table>
|
||||
<foreign_table_where>ORDER BY name</foreign_table_where>
|
||||
<items type="array">
|
||||
<numIndex index="0" type="array">
|
||||
<numIndex index="0"></numIndex>
|
||||
<numIndex index="1">0</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
<minitems>0</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.regionUid>
|
||||
<settings.season>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Saison:</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<items type="array">
|
||||
<numIndex index="0" type="array">
|
||||
<numIndex index="0">Winter</numIndex>
|
||||
<numIndex index="1">w</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="1" type="array">
|
||||
<numIndex index="0">Sommer</numIndex>
|
||||
<numIndex index="1">s</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
<minitems>1</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.season>
|
||||
</el>
|
||||
</ROOT>
|
||||
</sDEF>
|
||||
</sheets>
|
||||
</T3DataStructure>
|
||||
@@ -1,69 +0,0 @@
|
||||
<T3DataStructure>
|
||||
<meta>
|
||||
<langDisable>1</langDisable>
|
||||
</meta>
|
||||
<sheets>
|
||||
<sDEF>
|
||||
<ROOT>
|
||||
<TCEforms>
|
||||
<sheetTitle>Konfiguration</sheetTitle>
|
||||
</TCEforms>
|
||||
<type>array</type>
|
||||
<el>
|
||||
<settings.conceptUid>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Konzept:</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_concept</foreign_table>
|
||||
<foreign_table_where>AND tx_epproducts_domain_model_concept.hidden = 0 AND tx_epproducts_domain_model_concept.deleted = 0 ORDER BY tx_epproducts_domain_model_concept.name</foreign_table_where>
|
||||
<items type="array">
|
||||
<numIndex index="0" type="array">
|
||||
<numIndex index="0">Alle</numIndex>
|
||||
<numIndex index="1">0</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
<minitems>1</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.conceptUid>
|
||||
<settings.additionalConceptUids>
|
||||
<TCEforms>
|
||||
<label>Weitere Konzepte für Teaser:</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingleBox</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_concept</foreign_table>
|
||||
<foreign_table_where>AND tx_epproducts_domain_model_concept.hidden = 0 AND tx_epproducts_domain_model_concept.deleted = 0 ORDER BY tx_epproducts_domain_model_concept.name</foreign_table_where>
|
||||
<size>5</size>
|
||||
<minitems>0</minitems>
|
||||
<maxitems>10</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.additionalConceptUids>
|
||||
<settings.hideMoreLink>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Link zum Suchergebnis ausblenden:</label>
|
||||
<config>
|
||||
<type>check</type>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.hideMoreLink>
|
||||
<settings.hideHeader>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Header ausblenden:</label>
|
||||
<config>
|
||||
<type>check</type>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.hideHeader>
|
||||
</el>
|
||||
</ROOT>
|
||||
</sDEF>
|
||||
</sheets>
|
||||
</T3DataStructure>
|
||||
@@ -1,46 +0,0 @@
|
||||
<T3DataStructure>
|
||||
<meta>
|
||||
<langDisable>1</langDisable>
|
||||
</meta>
|
||||
<sheets>
|
||||
<sDEF>
|
||||
<ROOT>
|
||||
<TCEforms>
|
||||
<sheetTitle>Konfiguration</sheetTitle>
|
||||
</TCEforms>
|
||||
<type>array</type>
|
||||
<el>
|
||||
<settings.countryUid>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Land</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_country</foreign_table>
|
||||
<foreign_table_where>AND tx_epproducts_domain_model_country.hidden = 0 AND tx_epproducts_domain_model_country.deleted = 0 ORDER BY tx_epproducts_domain_model_country.name</foreign_table_where>
|
||||
<items type="array">
|
||||
<numIndex index="0" type="array">
|
||||
<numIndex index="0"></numIndex>
|
||||
<numIndex index="1">0</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
<minitems>0</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.countryUid>
|
||||
<settings.hideMoreLink>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Link zum Suchergebnis ausblenden:</label>
|
||||
<config>
|
||||
<type>check</type>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.hideMoreLink>
|
||||
</el>
|
||||
</ROOT>
|
||||
</sDEF>
|
||||
</sheets>
|
||||
</T3DataStructure>
|
||||
@@ -1,32 +0,0 @@
|
||||
<T3DataStructure>
|
||||
<meta>
|
||||
<langDisable>1</langDisable>
|
||||
</meta>
|
||||
<sheets>
|
||||
<sDEF>
|
||||
<ROOT>
|
||||
<TCEforms>
|
||||
<sheetTitle>Konfiguration</sheetTitle>
|
||||
</TCEforms>
|
||||
<type>array</type>
|
||||
<el>
|
||||
<settings.faqUids>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Fragen/Antworten</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectMultipleSideBySide</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_faq</foreign_table>
|
||||
<foreign_table_where>AND tx_epproducts_domain_model_faq.hidden = 0 AND tx_epproducts_domain_model_faq.deleted = 0 ORDER BY tx_epproducts_domain_model_faq.label</foreign_table_where>
|
||||
<minitems>1</minitems>
|
||||
<maxitems>50</maxitems>
|
||||
<size>10</size>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.faqUids>
|
||||
</el>
|
||||
</ROOT>
|
||||
</sDEF>
|
||||
</sheets>
|
||||
</T3DataStructure>
|
||||
@@ -1,46 +0,0 @@
|
||||
<T3DataStructure>
|
||||
<meta>
|
||||
<langDisable>1</langDisable>
|
||||
</meta>
|
||||
<sheets>
|
||||
<sDEF>
|
||||
<ROOT>
|
||||
<TCEforms>
|
||||
<sheetTitle>Konfiguration</sheetTitle>
|
||||
</TCEforms>
|
||||
<type>array</type>
|
||||
<el>
|
||||
<settings.hotelUid>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Hotel:</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_hotel</foreign_table>
|
||||
<foreign_table_where>AND tx_epproducts_domain_model_hotel.hidden = 0 AND tx_epproducts_domain_model_hotel.deleted = 0 ORDER BY tx_epproducts_domain_model_hotel.name</foreign_table_where>
|
||||
<items type="array">
|
||||
<numIndex index="0" type="array">
|
||||
<numIndex index="0">Alle</numIndex>
|
||||
<numIndex index="1">0</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
<minitems>0</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.hotelUid>
|
||||
<settings.hideMoreLink>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Link zum Suchergebnis ausblenden:</label>
|
||||
<config>
|
||||
<type>check</type>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.hideMoreLink>
|
||||
</el>
|
||||
</ROOT>
|
||||
</sDEF>
|
||||
</sheets>
|
||||
</T3DataStructure>
|
||||
@@ -1,51 +0,0 @@
|
||||
<T3DataStructure>
|
||||
<meta>
|
||||
<langDisable>1</langDisable>
|
||||
</meta>
|
||||
<sheets>
|
||||
<sDEF>
|
||||
<ROOT>
|
||||
<TCEforms>
|
||||
<sheetTitle>Konfiguration</sheetTitle>
|
||||
</TCEforms>
|
||||
<type>array</type>
|
||||
<el>
|
||||
<settings.productUid>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Produkt:</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_product</foreign_table>
|
||||
<foreign_table_where>AND tx_epproducts_domain_model_product.hidden = 0 AND tx_epproducts_domain_model_product.deleted = 0 ORDER BY tx_epproducts_domain_model_product.name_internal</foreign_table_where>
|
||||
<minitems>1</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.productUid>
|
||||
<settings.hotelUid>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Hotel:</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_hotel</foreign_table>
|
||||
<foreign_table_where>AND tx_epproducts_domain_model_hotel.hidden = 0 AND tx_epproducts_domain_model_hotel.deleted = 0 ORDER BY tx_epproducts_domain_model_hotel.name</foreign_table_where>
|
||||
<items type="array">
|
||||
<numIndex index="0" type="array">
|
||||
<numIndex index="0">Alle</numIndex>
|
||||
<numIndex index="1">0</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
<minitems>1</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.hotelUid>
|
||||
</el>
|
||||
</ROOT>
|
||||
</sDEF>
|
||||
</sheets>
|
||||
</T3DataStructure>
|
||||
@@ -1,217 +0,0 @@
|
||||
<T3DataStructure>
|
||||
<meta>
|
||||
<langDisable>1</langDisable>
|
||||
</meta>
|
||||
<sheets>
|
||||
<sDEF>
|
||||
<ROOT>
|
||||
<TCEforms>
|
||||
<sheetTitle>Konfiguration</sheetTitle>
|
||||
</TCEforms>
|
||||
<type>array</type>
|
||||
<el>
|
||||
<settings.columns>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Spalten:</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<items type="array">
|
||||
<numIndex index="0" type="array">
|
||||
<numIndex index="0">vierspaltig</numIndex>
|
||||
<numIndex index="1">4</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="1" type="array">
|
||||
<numIndex index="0">dreispaltig</numIndex>
|
||||
<numIndex index="1">3</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="2" type="array">
|
||||
<numIndex index="0">zweispaltig</numIndex>
|
||||
<numIndex index="1">2</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
<minitems>1</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.columns>
|
||||
<settings.countryUid>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Land:</label>
|
||||
<displayCond>FIELD:settings.productUid:REQ:FALSE</displayCond>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_country</foreign_table>
|
||||
<foreign_table_where>ORDER BY name</foreign_table_where>
|
||||
<items type="array">
|
||||
<numIndex index="0" type="array">
|
||||
<numIndex index="0">Keine Zuordnung</numIndex>
|
||||
<numIndex index="1">0</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
<minitems>0</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.countryUid>
|
||||
<settings.regionUid>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Gebiet:</label>
|
||||
<displayCond>FIELD:settings.productUid:REQ:FALSE</displayCond>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_region</foreign_table>
|
||||
<foreign_table_where>ORDER BY name</foreign_table_where>
|
||||
<items type="array">
|
||||
<numIndex index="0" type="array">
|
||||
<numIndex index="0">Keine Zuordnung</numIndex>
|
||||
<numIndex index="1">0</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
<minitems>0</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.regionUid>
|
||||
<settings.cityUid>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Ort:</label>
|
||||
<displayCond>FIELD:settings.productUid:REQ:FALSE</displayCond>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_city</foreign_table>
|
||||
<foreign_table_where>ORDER BY name</foreign_table_where>
|
||||
<items type="array">
|
||||
<numIndex index="0" type="array">
|
||||
<numIndex index="0">Keine Zuordnung</numIndex>
|
||||
<numIndex index="1">0</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
<minitems>0</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.cityUid>
|
||||
<settings.conceptUid>
|
||||
<TCEforms>
|
||||
<label>Konzept:</label>
|
||||
<displayCond>FIELD:settings.productUid:REQ:FALSE</displayCond>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_concept</foreign_table>
|
||||
<foreign_table_where>ORDER BY name</foreign_table_where>
|
||||
<items type="array">
|
||||
<numIndex index="0" type="array">
|
||||
<numIndex index="0">Keine Zuordnung</numIndex>
|
||||
<numIndex index="1">0</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
<minitems>0</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.conceptUid>
|
||||
<settings.productUid>
|
||||
<TCEforms>
|
||||
<label>Produkt:</label>
|
||||
<onChange>reload</onChange>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_product</foreign_table>
|
||||
<foreign_table_where>ORDER BY name_internal</foreign_table_where>
|
||||
<items type="array">
|
||||
<numIndex index="0" type="array">
|
||||
<numIndex index="0">Keine Zuordnung</numIndex>
|
||||
<numIndex index="1">0</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
<minitems>0</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.productUid>
|
||||
<settings.category>
|
||||
<TCEforms>
|
||||
<label>Kategorie:</label>
|
||||
<displayCond>FIELD:settings.productUid:REQ:TRUE</displayCond>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<items type="array">
|
||||
<numIndex index="0" type="array">
|
||||
<numIndex index="0">Alle</numIndex>
|
||||
<numIndex index="1">0</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="1" type="array">
|
||||
<numIndex index="0">Standard</numIndex>
|
||||
<numIndex index="1">1</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="2" type="array">
|
||||
<numIndex index="0">Basic</numIndex>
|
||||
<numIndex index="1">5</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="3" type="array">
|
||||
<numIndex index="0">Komfort</numIndex>
|
||||
<numIndex index="1">2</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="4" type="array">
|
||||
<numIndex index="0">Deluxe</numIndex>
|
||||
<numIndex index="1">3</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="5" type="array">
|
||||
<numIndex index="0">Superdeluxe</numIndex>
|
||||
<numIndex index="1">4</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
<minitems>0</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.category>
|
||||
<settings.type>
|
||||
<TCEforms>
|
||||
<label>Unterkunftsart:</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectCheckBox</renderType>
|
||||
<items type="array">
|
||||
<numIndex index="0" type="array">
|
||||
<numIndex index="0">Ferienwohnung</numIndex>
|
||||
<numIndex index="1">1</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="1" type="array">
|
||||
<numIndex index="0">Sportclub</numIndex>
|
||||
<numIndex index="1">2</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="2" type="array">
|
||||
<numIndex index="0">Apartment</numIndex>
|
||||
<numIndex index="1">3</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="3" type="array">
|
||||
<numIndex index="0">Gästerhaus</numIndex>
|
||||
<numIndex index="1">4</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="4" type="array">
|
||||
<numIndex index="0">Pension</numIndex>
|
||||
<numIndex index="1">5</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
<minitems>0</minitems>
|
||||
<maxitems>10</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.type>
|
||||
</el>
|
||||
</ROOT>
|
||||
</sDEF>
|
||||
</sheets>
|
||||
</T3DataStructure>
|
||||
-176
@@ -1,176 +0,0 @@
|
||||
<T3DataStructure>
|
||||
<meta>
|
||||
<langDisable>1</langDisable>
|
||||
</meta>
|
||||
<sheets>
|
||||
<sDEF>
|
||||
<ROOT>
|
||||
<TCEforms>
|
||||
<sheetTitle>Konfiguration</sheetTitle>
|
||||
</TCEforms>
|
||||
<type>array</type>
|
||||
<el>
|
||||
<settings.columns>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Spalten:</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<items type="array">
|
||||
<numIndex index="0" type="array">
|
||||
<numIndex index="0">vierspaltig</numIndex>
|
||||
<numIndex index="1">4</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="1" type="array">
|
||||
<numIndex index="0">dreispaltig</numIndex>
|
||||
<numIndex index="1">3</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="2" type="array">
|
||||
<numIndex index="0">zweispaltig</numIndex>
|
||||
<numIndex index="1">2</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
<minitems>1</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.columns>
|
||||
<settings.countryUid>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Land:</label>
|
||||
<displayCond>FIELD:settings.productUid:REQ:FALSE</displayCond>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_country</foreign_table>
|
||||
<foreign_table_where>ORDER BY name</foreign_table_where>
|
||||
<items type="array">
|
||||
<numIndex index="0" type="array">
|
||||
<numIndex index="0">Keine Zuordnung</numIndex>
|
||||
<numIndex index="1">0</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
<minitems>0</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.countryUid>
|
||||
<settings.regionUid>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Gebiet:</label>
|
||||
<displayCond>FIELD:settings.productUid:REQ:FALSE</displayCond>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_region</foreign_table>
|
||||
<foreign_table_where>ORDER BY name</foreign_table_where>
|
||||
<items type="array">
|
||||
<numIndex index="0" type="array">
|
||||
<numIndex index="0">Keine Zuordnung</numIndex>
|
||||
<numIndex index="1">0</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
<minitems>0</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.regionUid>
|
||||
<settings.productUid>
|
||||
<TCEforms>
|
||||
<label>Produkt:</label>
|
||||
<onChange>reload</onChange>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_product</foreign_table>
|
||||
<foreign_table_where>ORDER BY name_internal</foreign_table_where>
|
||||
<items type="array">
|
||||
<numIndex index="0" type="array">
|
||||
<numIndex index="0">Keine Zuordnung</numIndex>
|
||||
<numIndex index="1">0</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
<minitems>0</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.productUid>
|
||||
<settings.category>
|
||||
<TCEforms>
|
||||
<label>Kategorie:</label>
|
||||
<displayCond>FIELD:settings.productUid:REQ:TRUE</displayCond>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<items type="array">
|
||||
<numIndex index="0" type="array">
|
||||
<numIndex index="0">Alle</numIndex>
|
||||
<numIndex index="1">0</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="1" type="array">
|
||||
<numIndex index="0">Standard</numIndex>
|
||||
<numIndex index="1">1</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="2" type="array">
|
||||
<numIndex index="0">Basic</numIndex>
|
||||
<numIndex index="1">5</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="3" type="array">
|
||||
<numIndex index="0">Komfort</numIndex>
|
||||
<numIndex index="1">2</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="4" type="array">
|
||||
<numIndex index="0">Deluxe</numIndex>
|
||||
<numIndex index="1">3</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="5" type="array">
|
||||
<numIndex index="0">Superdeluxe</numIndex>
|
||||
<numIndex index="1">4</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
<minitems>0</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.category>
|
||||
<settings.type>
|
||||
<TCEforms>
|
||||
<label>Unterkunftsart:</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectCheckBox</renderType>
|
||||
<items type="array">
|
||||
<numIndex index="0" type="array">
|
||||
<numIndex index="0">Ferienwohnung</numIndex>
|
||||
<numIndex index="1">1</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="1" type="array">
|
||||
<numIndex index="0">Sportclub</numIndex>
|
||||
<numIndex index="1">2</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="2" type="array">
|
||||
<numIndex index="0">Apartment</numIndex>
|
||||
<numIndex index="1">3</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="3" type="array">
|
||||
<numIndex index="0">Gästerhaus</numIndex>
|
||||
<numIndex index="1">4</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="4" type="array">
|
||||
<numIndex index="0">Pension</numIndex>
|
||||
<numIndex index="1">5</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
<minitems>0</minitems>
|
||||
<maxitems>10</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.type>
|
||||
</el>
|
||||
</ROOT>
|
||||
</sDEF>
|
||||
</sheets>
|
||||
</T3DataStructure>
|
||||
@@ -1,47 +0,0 @@
|
||||
<T3DataStructure>
|
||||
<meta>
|
||||
<langDisable>1</langDisable>
|
||||
</meta>
|
||||
<sheets>
|
||||
<sDEF>
|
||||
<ROOT>
|
||||
<TCEforms>
|
||||
<sheetTitle>Konfiguration</sheetTitle>
|
||||
</TCEforms>
|
||||
<type>array</type>
|
||||
<el>
|
||||
<settings.hotelUids>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Unterkünfte</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectMultipleSideBySide</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_hotel</foreign_table>
|
||||
<foreign_table_where>AND tx_epproducts_domain_model_hotel.latitude != "" AND tx_epproducts_domain_model_hotel.longitude != "" ORDER BY name</foreign_table_where>
|
||||
<minitems>0</minitems>
|
||||
<maxitems>50</maxitems>
|
||||
<size>10</size>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.hotelUids>
|
||||
<settings.productUids>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Produkte</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectMultipleSideBySide</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_product</foreign_table>
|
||||
<foreign_table_where>AND tx_epproducts_domain_model_product.detail_page != 0 ORDER BY name_internal</foreign_table_where>
|
||||
<minitems>0</minitems>
|
||||
<maxitems>50</maxitems>
|
||||
<size>10</size>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.productUids>
|
||||
</el>
|
||||
</ROOT>
|
||||
</sDEF>
|
||||
</sheets>
|
||||
</T3DataStructure>
|
||||
@@ -1,65 +0,0 @@
|
||||
<T3DataStructure>
|
||||
<meta>
|
||||
<langDisable>1</langDisable>
|
||||
</meta>
|
||||
<sheets>
|
||||
<sDEF>
|
||||
<ROOT>
|
||||
<TCEforms>
|
||||
<sheetTitle>Konfiguration</sheetTitle>
|
||||
</TCEforms>
|
||||
<type>array</type>
|
||||
<el>
|
||||
<switchableControllerActions>
|
||||
<TCEforms>
|
||||
<label>Modus</label>
|
||||
<onChange>reload</onChange>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<default>Pricetable->event</default>
|
||||
<items type="array">
|
||||
<numIndex index="1" type="array">
|
||||
<numIndex index="0">Preistabelle Eventreise</numIndex>
|
||||
<numIndex index="1">Pricetable->event</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</switchableControllerActions>
|
||||
<settings.forcePartnerIdSelect>
|
||||
<TCEforms>
|
||||
<label>Partner ID Auswahl anzeigen:</label>
|
||||
<config>
|
||||
<type>check</type>
|
||||
<default>0</default>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.forcePartnerIdSelect>
|
||||
<settings.partnerIdSelectLabel>
|
||||
<TCEforms>
|
||||
<label>Partner ID Auswahl Text:</label>
|
||||
<config>
|
||||
<type>input</type>
|
||||
<eval>trim</eval>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.partnerIdSelectLabel>
|
||||
<settings.productUid>
|
||||
<TCEforms>
|
||||
<label>Produkt:</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_product</foreign_table>
|
||||
<foreign_table_where>AND tx_epproducts_domain_model_product.hidden = 0 AND tx_epproducts_domain_model_product.deleted = 0 ORDER BY tx_epproducts_domain_model_product.name_internal</foreign_table_where>
|
||||
<minitems>1</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.productUid>
|
||||
</el>
|
||||
</ROOT>
|
||||
</sDEF>
|
||||
</sheets>
|
||||
</T3DataStructure>
|
||||
@@ -1,54 +0,0 @@
|
||||
<T3DataStructure>
|
||||
<meta>
|
||||
<langDisable>1</langDisable>
|
||||
</meta>
|
||||
<sheets>
|
||||
<sDEF>
|
||||
<ROOT>
|
||||
<TCEforms>
|
||||
<sheetTitle>Konfiguration</sheetTitle>
|
||||
</TCEforms>
|
||||
<type>array</type>
|
||||
<el>
|
||||
<settings.regionUid>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Gebiet:</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_region</foreign_table>
|
||||
<foreign_table_where>AND tx_epproducts_domain_model_region.hidden = 0 AND tx_epproducts_domain_model_region.deleted = 0 ORDER BY tx_epproducts_domain_model_region.name</foreign_table_where>
|
||||
<minitems>1</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.regionUid>
|
||||
<settings.additionalRegionUids>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Weitere Gebiete für Teaser:</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectMultipleSideBySide</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_region</foreign_table>
|
||||
<foreign_table_where>AND tx_epproducts_domain_model_region.hidden = 0 AND tx_epproducts_domain_model_region.deleted = 0 ORDER BY tx_epproducts_domain_model_region.name</foreign_table_where>
|
||||
<minitems>0</minitems>
|
||||
<maxitems>5</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.additionalRegionUids>
|
||||
<settings.hideMoreLink>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Link zum Suchergebnis ausblenden:</label>
|
||||
<config>
|
||||
<type>check</type>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.hideMoreLink>
|
||||
</el>
|
||||
</ROOT>
|
||||
</sDEF>
|
||||
</sheets>
|
||||
</T3DataStructure>
|
||||
@@ -1,53 +0,0 @@
|
||||
<T3DataStructure>
|
||||
<meta>
|
||||
<langDisable>1</langDisable>
|
||||
</meta>
|
||||
<sheets>
|
||||
<sDEF>
|
||||
<ROOT>
|
||||
<TCEforms>
|
||||
<sheetTitle>Konfiguration</sheetTitle>
|
||||
</TCEforms>
|
||||
<type>array</type>
|
||||
<el>
|
||||
<settings.countryUid>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Land:</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_country</foreign_table>
|
||||
<foreign_table_where>ORDER BY name</foreign_table_where>
|
||||
<minitems>1</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.countryUid>
|
||||
<settings.season>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Saison:</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectSingle</renderType>
|
||||
<items type="array">
|
||||
<numIndex index="0" type="array">
|
||||
<numIndex index="0">Winter</numIndex>
|
||||
<numIndex index="1">w</numIndex>
|
||||
</numIndex>
|
||||
<numIndex index="1" type="array">
|
||||
<numIndex index="0">Sommer</numIndex>
|
||||
<numIndex index="1">s</numIndex>
|
||||
</numIndex>
|
||||
</items>
|
||||
<minitems>1</minitems>
|
||||
<maxitems>1</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.season>
|
||||
</el>
|
||||
</ROOT>
|
||||
</sDEF>
|
||||
</sheets>
|
||||
</T3DataStructure>
|
||||
@@ -1,32 +0,0 @@
|
||||
<T3DataStructure>
|
||||
<meta>
|
||||
<langDisable>1</langDisable>
|
||||
</meta>
|
||||
<sheets>
|
||||
<sDEF>
|
||||
<ROOT>
|
||||
<TCEforms>
|
||||
<sheetTitle>Konfiguration</sheetTitle>
|
||||
</TCEforms>
|
||||
<type>array</type>
|
||||
<el>
|
||||
<settings.regionUids>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Gebiete einschränken</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectMultipleSideBySide</renderType>
|
||||
<foreign_table>tx_epproducts_domain_model_region</foreign_table>
|
||||
<foreign_table_where>AND tx_epproducts_domain_model_region.snowreport > 0 ORDER BY name</foreign_table_where>
|
||||
<minitems>0</minitems>
|
||||
<maxitems>99</maxitems>
|
||||
<size>10</size>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.regionUids>
|
||||
</el>
|
||||
</ROOT>
|
||||
</sDEF>
|
||||
</sheets>
|
||||
</T3DataStructure>
|
||||
@@ -1,53 +0,0 @@
|
||||
<T3DataStructure>
|
||||
<meta>
|
||||
<langDisable>1</langDisable>
|
||||
</meta>
|
||||
<sheets>
|
||||
<sDEF>
|
||||
<ROOT>
|
||||
<TCEforms>
|
||||
<sheetTitle>Konfiguration</sheetTitle>
|
||||
</TCEforms>
|
||||
<type>array</type>
|
||||
<el>
|
||||
<settings.teamListPID>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Listenansicht PID</label>
|
||||
<config>
|
||||
<type>input</type>
|
||||
<size>20</size>
|
||||
<eval>required</eval>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.teamListPID>
|
||||
<settings.teamShowPID>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Einzelansicht PID</label>
|
||||
<config>
|
||||
<type>input</type>
|
||||
<size>20</size>
|
||||
<eval>required</eval>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.teamShowPID>
|
||||
<settings.teamCategories>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Auf Kategorie beschränken</label>
|
||||
<config>
|
||||
<type>select</type>
|
||||
<renderType>selectMultipleSideBySide</renderType>
|
||||
<enableMultiSelectFilterTextfield>1</enableMultiSelectFilterTextfield>
|
||||
<foreign_table>sys_category</foreign_table>
|
||||
<minitems>0</minitems>
|
||||
<maxitems>99</maxitems>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.teamCategories>
|
||||
</el>
|
||||
</ROOT>
|
||||
</sDEF>
|
||||
</sheets>
|
||||
</T3DataStructure>
|
||||
@@ -2,15 +2,6 @@
|
||||
|
||||
return [
|
||||
'frontend' => [
|
||||
'ep/staticsearch' => [
|
||||
'target' => \EP\EpProducts\Middleware\StaticSearchParamsMiddleware::class,
|
||||
'before' => [
|
||||
'typo3/cms-redirects/redirecthandler',
|
||||
],
|
||||
'after' => [
|
||||
'typo3/cms-frontend/static-route-resolver',
|
||||
],
|
||||
],
|
||||
'ep/productapi' => [
|
||||
'target' => \EP\EpProducts\Middleware\ApiMiddleware::class,
|
||||
'before' => [
|
||||
@@ -29,11 +20,5 @@ return [
|
||||
'typo3/cms-frontend/page-argument-validator',
|
||||
],
|
||||
],
|
||||
'ep/staging-environment' => [
|
||||
'target' => \EP\EpProducts\Middleware\StagingEnvironmentMiddleware::class,
|
||||
'after' => [
|
||||
'typo3/cms-frontend/authentication',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
@@ -8,11 +8,8 @@ services:
|
||||
resource: '../Classes/*'
|
||||
exclude: '../Classes/Domain/Model/*'
|
||||
|
||||
EP\EpProducts\EventListener\SystemInformationToolbarListener:
|
||||
tags:
|
||||
- name: event.listener
|
||||
identifier: 'epToolbarListener'
|
||||
event: TYPO3\CMS\Backend\Backend\Event\SystemInformationToolbarCollectorEvent
|
||||
EP\EpProducts\Service\ProductImportSource:
|
||||
alias: EP\EpProducts\Service\ApiImportSource
|
||||
|
||||
cache.ep_cache:
|
||||
class: TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
|
||||
@@ -28,10 +25,6 @@ services:
|
||||
arguments:
|
||||
$cache: '@cache.ep_cache'
|
||||
|
||||
EP\EpProducts\Controller\AjaxCalendarController:
|
||||
arguments:
|
||||
$cache: '@cache.ep_cache'
|
||||
|
||||
EP\EpProducts\Service\MyEpImageService:
|
||||
arguments:
|
||||
$cache: '@cache.ep_cache'
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
defined('TYPO3_MODE') or die();
|
||||
|
||||
call_user_func(function() {
|
||||
|
||||
$temporaryColumns = [
|
||||
'tx_epproducts_reseller' => [
|
||||
'label' => 'Vertragspartner',
|
||||
'config' => [
|
||||
'type' => 'select',
|
||||
'renderType' => 'selectSingle',
|
||||
'foreign_table' => 'tx_epproducts_domain_model_reseller',
|
||||
'foreign_table_where' => 'ORDER BY title',
|
||||
'items' => [
|
||||
['Keine Zuordnung', 0],
|
||||
],
|
||||
'minitems' => 0,
|
||||
'maxitems' => 1,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns(
|
||||
'sys_domain',
|
||||
$temporaryColumns
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes(
|
||||
'sys_domain',
|
||||
'tx_epproducts_reseller',
|
||||
'',
|
||||
'before:redirectTo'
|
||||
);
|
||||
|
||||
});
|
||||
@@ -5,18 +5,6 @@ defined('TYPO3_MODE') or die();
|
||||
|
||||
call_user_func(function () {
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'searchbar',
|
||||
'Suchschlitz'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'searchresult',
|
||||
'Suchergebnis'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'product_detail',
|
||||
@@ -35,132 +23,6 @@ call_user_func(function () {
|
||||
'Buchungstabelle'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'country_detail',
|
||||
'Land'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'region_teasergroup',
|
||||
'Gebiet: Teaser'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'region_detail',
|
||||
'Gebiet: Details'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'city_teasergroup',
|
||||
'Ort: Teaser'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'city_detail',
|
||||
'Ort: Details'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'hotel_teasergroup',
|
||||
'Hotel: Teaser'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'hotel_teasergroup_nodate',
|
||||
'Hotel: Teaser (terminunabhängig)'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'hotel_detail',
|
||||
'Hotel: Details'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'hotel_detail_event',
|
||||
'Hotel: Details (Event)'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'concept_teasergroup',
|
||||
'Konzept: Teaser'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'concept_detail',
|
||||
'Konzept: Details'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'snowreport_list',
|
||||
'Schneehöhen'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'teammembers',
|
||||
'Team'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'faq',
|
||||
'FAQ'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'newsletter',
|
||||
'Newsletter'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'newsletter_subscription',
|
||||
'Newsletter-/RA-Registrierung'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'maps',
|
||||
'Übersichtskarte Hotels/Produkte'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'pricetable',
|
||||
'Preistabelle'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'reseller',
|
||||
'Vertriebspartner Export'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'watchlist',
|
||||
'Merkliste'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'travelinfo',
|
||||
'Reiseinformationen'
|
||||
);
|
||||
|
||||
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['epproducts_product_detail'] = 'pi_flexform';
|
||||
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
|
||||
'epproducts_product_detail', 'FILE:EXT:ep_products/Configuration/FlexForms/flexform_product_detail.xml'
|
||||
@@ -178,94 +40,4 @@ call_user_func(function () {
|
||||
'FILE:EXT:ep_products/Configuration/FlexForms/flexform_product_pricetable.xml'
|
||||
);
|
||||
|
||||
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['epproducts_country_detail'] = 'pi_flexform';
|
||||
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
|
||||
'epproducts_country_detail',
|
||||
'FILE:EXT:ep_products/Configuration/FlexForms/flexform_country.xml'
|
||||
);
|
||||
|
||||
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['epproducts_region_teasergroup'] = 'pi_flexform';
|
||||
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
|
||||
'epproducts_region_teasergroup',
|
||||
'FILE:EXT:ep_products/Configuration/FlexForms/flexform_region_teaser.xml'
|
||||
);
|
||||
|
||||
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['epproducts_region_detail'] = 'pi_flexform';
|
||||
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
|
||||
'epproducts_region_detail',
|
||||
'FILE:EXT:ep_products/Configuration/FlexForms/flexform_region_detail.xml'
|
||||
);
|
||||
|
||||
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['epproducts_city_teasergroup'] = 'pi_flexform';
|
||||
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
|
||||
'epproducts_city_teasergroup',
|
||||
'FILE:EXT:ep_products/Configuration/FlexForms/flexform_city_teaser.xml'
|
||||
);
|
||||
|
||||
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['epproducts_city_detail'] = 'pi_flexform';
|
||||
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
|
||||
'epproducts_city_detail',
|
||||
'FILE:EXT:ep_products/Configuration/FlexForms/flexform_city_detail.xml'
|
||||
);
|
||||
|
||||
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['epproducts_hotel_teasergroup'] = 'pi_flexform';
|
||||
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
|
||||
'epproducts_hotel_teasergroup',
|
||||
'FILE:EXT:ep_products/Configuration/FlexForms/flexform_hotel_teaser.xml'
|
||||
);
|
||||
|
||||
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['epproducts_hotel_teasergroup_nodate'] = 'pi_flexform';
|
||||
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
|
||||
'epproducts_hotel_teasergroup_nodate',
|
||||
'FILE:EXT:ep_products/Configuration/FlexForms/flexform_hotel_teaser_date_independent.xml'
|
||||
);
|
||||
|
||||
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['epproducts_hotel_detail'] = 'pi_flexform';
|
||||
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
|
||||
'epproducts_hotel_detail',
|
||||
'FILE:EXT:ep_products/Configuration/FlexForms/flexform_hotel_detail.xml'
|
||||
);
|
||||
|
||||
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['epproducts_hotel_detail_event'] = 'pi_flexform';
|
||||
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
|
||||
'epproducts_hotel_detail_event',
|
||||
'FILE:EXT:ep_products/Configuration/FlexForms/flexform_hotel_detail_event.xml'
|
||||
);
|
||||
|
||||
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['epproducts_concept_detail'] = 'pi_flexform';
|
||||
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
|
||||
'epproducts_concept_detail',
|
||||
'FILE:EXT:ep_products/Configuration/FlexForms/flexform_concept_detail.xml'
|
||||
);
|
||||
|
||||
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['epproducts_faq'] = 'pi_flexform';
|
||||
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
|
||||
'epproducts_faq',
|
||||
'FILE:EXT:ep_products/Configuration/FlexForms/flexform_faq.xml'
|
||||
);
|
||||
|
||||
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['epproducts_maps'] = 'pi_flexform';
|
||||
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
|
||||
'epproducts_maps',
|
||||
'FILE:EXT:ep_products/Configuration/FlexForms/flexform_maps.xml'
|
||||
);
|
||||
|
||||
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['epproducts_pricetable'] = 'pi_flexform';
|
||||
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
|
||||
'epproducts_pricetable',
|
||||
'FILE:EXT:ep_products/Configuration/FlexForms/flexform_pricetable.xml'
|
||||
);
|
||||
|
||||
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['epproducts_snowreport_list'] = 'pi_flexform';
|
||||
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
|
||||
'epproducts_snowreport_list',
|
||||
'FILE:EXT:ep_products/Configuration/FlexForms/flexform_snowreport.xml'
|
||||
);
|
||||
|
||||
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['epproducts_teammembers'] = 'pi_flexform';
|
||||
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
|
||||
'epproducts_teammembers',
|
||||
'FILE:EXT:ep_products/Configuration/FlexForms/flexform_teammembers.xml'
|
||||
);
|
||||
|
||||
});
|
||||
-258
@@ -1,258 +0,0 @@
|
||||
<?php
|
||||
return [
|
||||
'ctrl' => [
|
||||
'title' => 'LLL:EXT:ep_products/Resources/Private/Language/locallang.xlf:tx_epproducts_domain_model_staticsearchparams',
|
||||
'label' => 'name',
|
||||
'prependAtCopy' => '[COPY %s]',
|
||||
'default_sortby' => 'ORDER BY name',
|
||||
'tstamp' => 'tstamp',
|
||||
'crdate' => 'crdate',
|
||||
'cruser_id' => 'cruser_id',
|
||||
'dividers2tabs' => true,
|
||||
'versioningWS' => true,
|
||||
'languageField' => 'sys_language_uid',
|
||||
'transOrigPointerField' => 'l10n_parent',
|
||||
'transOrigDiffSourceField' => 'l10n_diffsource',
|
||||
'delete' => 'deleted',
|
||||
'enablecolumns' => [
|
||||
'disabled' => 'hidden',
|
||||
'starttime' => 'starttime',
|
||||
'endtime' => 'endtime',
|
||||
],
|
||||
'searchFields' => 'name,path_segment',
|
||||
'iconfile' => 'EXT:ep_theme/Resources/Public/images/icon_ce.svg',
|
||||
],
|
||||
'types' => [
|
||||
'1' => [
|
||||
'showitem' => 'name, path_segment, country, region, concept, hotel, product, date_from,
|
||||
date_to, hotel_types, bus, pax',
|
||||
],
|
||||
],
|
||||
'palettes' => [],
|
||||
'columns' => [
|
||||
|
||||
'sys_language_uid' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
|
||||
'config' => [
|
||||
'type' => 'select',
|
||||
'default' => 0,
|
||||
'renderType' => 'selectSingle',
|
||||
'foreign_table' => 'sys_language',
|
||||
'foreign_table_where' => 'ORDER BY sys_language.title',
|
||||
'items' => [
|
||||
['LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.allLanguages', -1],
|
||||
['LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.default_value', 0]
|
||||
],
|
||||
],
|
||||
],
|
||||
'l10n_parent' => [
|
||||
'displayCond' => 'FIELD:sys_language_uid:>:0',
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent',
|
||||
'config' => [
|
||||
'type' => 'select',
|
||||
'default' => 0,
|
||||
'renderType' => 'selectSingle',
|
||||
'items' => [
|
||||
['', 0],
|
||||
],
|
||||
'foreign_table' => 'tx_epproducts_domain_model_staticsearchparams',
|
||||
'foreign_table_where' => 'AND tx_epproducts_domain_model_staticsearchparams.pid=###CURRENT_PID### AND tx_epproducts_domain_model_staticsearchparams.sys_language_uid IN (-1,0)',
|
||||
],
|
||||
],
|
||||
'l10n_diffsource' => [
|
||||
'config' => [
|
||||
'type' => 'passthrough',
|
||||
],
|
||||
],
|
||||
|
||||
't3ver_label' => [
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.versionLabel',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'size' => 30,
|
||||
'max' => 255,
|
||||
]
|
||||
],
|
||||
|
||||
'hidden' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'LLL:EXT:ep_products/Resources/Private/Language/locallang.xlf:tx_epproducts_domain_model_product.hidden',
|
||||
'config' => [
|
||||
'type' => 'check',
|
||||
],
|
||||
],
|
||||
'starttime' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.starttime',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'size' => 13,
|
||||
'eval' => 'datetime',
|
||||
'checkbox' => 0,
|
||||
'default' => 0,
|
||||
'behaviour' => [
|
||||
'allowLanguageSynchronization' => true,
|
||||
],
|
||||
'renderType' => 'inputDateTime',
|
||||
],
|
||||
],
|
||||
'endtime' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.endtime',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'size' => 13,
|
||||
'eval' => 'datetime',
|
||||
'checkbox' => 0,
|
||||
'default' => 0,
|
||||
'behaviour' => [
|
||||
'allowLanguageSynchronization' => true,
|
||||
],
|
||||
'renderType' => 'inputDateTime',
|
||||
],
|
||||
],
|
||||
|
||||
'bus' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'Bus',
|
||||
'config' => [
|
||||
'type' => 'check',
|
||||
],
|
||||
],
|
||||
'name' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'Name',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'cols' => 30,
|
||||
'eval' => 'trim,required'
|
||||
],
|
||||
],
|
||||
'path_segment' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'URL Segment',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'size' => 30,
|
||||
'eval' => 'trim,required,unique,alphanum_x,lower'
|
||||
],
|
||||
],
|
||||
'concept' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'Konzept',
|
||||
'config' => [
|
||||
'type' => 'select',
|
||||
'renderType' => 'selectSingleBox',
|
||||
'foreign_table' => 'tx_epproducts_domain_model_concept',
|
||||
'foreign_table_where' => 'AND 1=1 ORDER BY name',
|
||||
'minItems' => 0,
|
||||
'maxitems' => 10,
|
||||
'size' => 5,
|
||||
'items' => [
|
||||
[ 'Keine Auswahl', 0 ],
|
||||
]
|
||||
],
|
||||
],
|
||||
'country' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'Land',
|
||||
'config' => [
|
||||
'type' => 'select',
|
||||
'default' => 0,
|
||||
'renderType' => 'selectSingle',
|
||||
'foreign_table' => 'tx_epproducts_domain_model_country',
|
||||
'foreign_table_where' => 'AND 1=1 ORDER BY name',
|
||||
'minitems' => 0,
|
||||
'maxitems' => 1,
|
||||
'items' => [
|
||||
[ 'Keine Auswahl', 0 ],
|
||||
]
|
||||
],
|
||||
],
|
||||
'region' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'Gebiet',
|
||||
'config' => [
|
||||
'type' => 'select',
|
||||
'default' => 0,
|
||||
'renderType' => 'selectSingle',
|
||||
'foreign_table' => 'tx_epproducts_domain_model_region',
|
||||
'foreign_table_where' => 'AND 1=1 ORDER BY name',
|
||||
'minitems' => 0,
|
||||
'maxitems' => 1,
|
||||
'items' => [
|
||||
[ 'Keine Auswahl', 0 ],
|
||||
]
|
||||
],
|
||||
],
|
||||
'hotel' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'Hotel',
|
||||
'config' => [
|
||||
'type' => 'select',
|
||||
'default' => 0,
|
||||
'renderType' => 'selectSingle',
|
||||
'foreign_table' => 'tx_epproducts_domain_model_hotel',
|
||||
'foreign_table_where' => 'AND 1=1 ORDER BY tx_epproducts_domain_model_hotel.name',
|
||||
'minitems' => 0,
|
||||
'maxitems' => 1,
|
||||
'items' => [
|
||||
[ 'Keine Auswahl', 0 ],
|
||||
]
|
||||
],
|
||||
],
|
||||
'hotel_types' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'Unterkunftsarten',
|
||||
'config' => [
|
||||
'type' => 'select',
|
||||
'renderType' => 'selectCheckBox',
|
||||
'items' => [
|
||||
[ 'Keine Auswahl', 0 ],
|
||||
[ 'Standard', \EP\EpProducts\Domain\Model\Hotel::CATEGORY_STANDARD ],
|
||||
[ 'Komfort', \EP\EpProducts\Domain\Model\Hotel::CATEGORY_COMFORT ],
|
||||
[ 'Deluxe', \EP\EpProducts\Domain\Model\Hotel::CATEGORY_DELUXE ],
|
||||
[ 'Superdeluxe', \EP\EpProducts\Domain\Model\Hotel::CATEGORY_SUPER_DELUXE ],
|
||||
],
|
||||
'minitems' => 0,
|
||||
'maxitems' => 99,
|
||||
]
|
||||
],
|
||||
'date_from' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'Datum von',
|
||||
'config' => [
|
||||
'dbType' => 'date',
|
||||
'type' => 'input',
|
||||
'size' => 7,
|
||||
'eval' => 'date',
|
||||
'checkbox' => 0,
|
||||
'default' => '0000-00-00',
|
||||
'renderType' => 'inputDateTime',
|
||||
]
|
||||
],
|
||||
'date_to' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'Datum bis',
|
||||
'config' => [
|
||||
'dbType' => 'date',
|
||||
'type' => 'input',
|
||||
'size' => 7,
|
||||
'eval' => 'date',
|
||||
'checkbox' => 0,
|
||||
'default' => '0000-00-00',
|
||||
'renderType' => 'inputDateTime',
|
||||
]
|
||||
],
|
||||
'pax' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'Personen',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'size' => 2,
|
||||
'eval' => 'int',
|
||||
]
|
||||
]
|
||||
],
|
||||
];
|
||||
@@ -1,374 +0,0 @@
|
||||
<?php
|
||||
return [
|
||||
'ctrl' => [
|
||||
'title' => 'Reiseinformationen',
|
||||
'default_sortby' => 'ORDER BY title',
|
||||
'label' => 'title',
|
||||
'prependAtCopy' => '[COPY %s]',
|
||||
'tstamp' => 'tstamp',
|
||||
'crdate' => 'crdate',
|
||||
'cruser_id' => 'cruser_id',
|
||||
'origUid' => 't3_origuid',
|
||||
'dividers2tabs' => true,
|
||||
'versioningWS' => true,
|
||||
'languageField' => 'sys_language_uid',
|
||||
'transOrigPointerField' => 'l10n_parent',
|
||||
'transOrigDiffSourceField' => 'l10n_diffsource',
|
||||
'delete' => 'deleted',
|
||||
'enablecolumns' => [
|
||||
'disabled' => 'hidden',
|
||||
'starttime' => 'starttime',
|
||||
'endtime' => 'endtime',
|
||||
],
|
||||
'searchFields' => 'title,travel_code',
|
||||
'iconfile' => 'EXT:ep_theme/Resources/Public/images/icon_ce.svg',
|
||||
],
|
||||
'types' => [
|
||||
'1' => [
|
||||
'showitem' => '--palette--;;basics,--div--;Texte,--palette--;;text,--div--;Bilder,--palette--;;images',
|
||||
],
|
||||
],
|
||||
'palettes' => [
|
||||
'basics' => ['showitem' => 'title,path_segment,--linebreak--,travel_code,hide_address,--linebreak--,links,
|
||||
--linebreak--,teasers'],
|
||||
'text' => ['showitem' => 'subline,headline,--linebreak--,intro_text,--linebreak--, bus_info_text,--linebreak--,
|
||||
departure_text,--linebreak--,footer_text,--linebreak--,self_arranged_text,--linebreak--,additional_info,
|
||||
--linebreak--,important_phone_numbers,--linebreak--,important_links'],
|
||||
'images' => ['showitem' => 'header_image,--linebreak--,footer_image'],
|
||||
],
|
||||
'columns' => [
|
||||
'sys_language_uid' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
|
||||
'config' => [
|
||||
'type' => 'select',
|
||||
'renderType' => 'selectSingle',
|
||||
'foreign_table' => 'sys_language',
|
||||
'foreign_table_where' => 'ORDER BY sys_language.title',
|
||||
'items' => [
|
||||
['LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.allLanguages', -1],
|
||||
['LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.default_value', 0]
|
||||
],
|
||||
'default' => 0,
|
||||
],
|
||||
],
|
||||
'l10n_parent' => [
|
||||
'displayCond' => 'FIELD:sys_language_uid:>:0',
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent',
|
||||
'config' => [
|
||||
'type' => 'select',
|
||||
'default' => 0,
|
||||
'renderType' => 'selectSingle',
|
||||
'items' => [
|
||||
['', 0],
|
||||
],
|
||||
'foreign_table' => 'tx_epproducts_domain_model_travelinfo',
|
||||
'foreign_table_where' => 'AND tx_epproducts_domain_model_travelinfo.pid=###CURRENT_PID### AND tx_epproducts_domain_model_travelinfo.sys_language_uid IN (-1,0)',
|
||||
],
|
||||
],
|
||||
'l10n_diffsource' => [
|
||||
'config' => [
|
||||
'type' => 'passthrough',
|
||||
],
|
||||
],
|
||||
|
||||
't3ver_label' => [
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.versionLabel',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'size' => 30,
|
||||
'max' => 255,
|
||||
]
|
||||
],
|
||||
|
||||
'hidden' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.hidden',
|
||||
'config' => [
|
||||
'type' => 'check',
|
||||
],
|
||||
],
|
||||
'starttime' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.starttime',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'size' => 13,
|
||||
'eval' => 'datetime',
|
||||
'checkbox' => 0,
|
||||
'default' => 0,
|
||||
'behaviour' => [
|
||||
'allowLanguageSynchronization' => true,
|
||||
],
|
||||
'renderType' => 'inputDateTime',
|
||||
],
|
||||
],
|
||||
'endtime' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.endtime',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'size' => 13,
|
||||
'eval' => 'datetime',
|
||||
'checkbox' => 0,
|
||||
'default' => 0,
|
||||
'behaviour' => [
|
||||
'allowLanguageSynchronization' => true,
|
||||
],
|
||||
'renderType' => 'inputDateTime',
|
||||
],
|
||||
],
|
||||
|
||||
'title' => [
|
||||
'exclude' => false,
|
||||
'label' => 'Titel (nur intern genutzt)',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'size' => 30,
|
||||
'eval' => 'trim,required'
|
||||
],
|
||||
],
|
||||
'subline' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'Subline',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'size' => 30,
|
||||
'eval' => 'trim'
|
||||
],
|
||||
],
|
||||
'headline' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'Headline',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'size' => 30,
|
||||
'eval' => 'trim'
|
||||
],
|
||||
],
|
||||
'header_image' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'Headerbild',
|
||||
'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig(
|
||||
'header_image',
|
||||
[
|
||||
'appearance' => [
|
||||
'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference'
|
||||
],
|
||||
'overrideChildTca' => [
|
||||
'types' => [
|
||||
\TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [
|
||||
'showitem' => '
|
||||
--palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
|
||||
--palette--;;filePalette',
|
||||
],
|
||||
],
|
||||
],
|
||||
'maxitems' => 1,
|
||||
'minitems' => 1,
|
||||
],
|
||||
$GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']
|
||||
),
|
||||
],
|
||||
'footer_image' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'Footerbild',
|
||||
'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig(
|
||||
'footer_image',
|
||||
[
|
||||
'appearance' => [
|
||||
'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference'
|
||||
],
|
||||
'overrideChildTca' => [
|
||||
'types' => [
|
||||
\TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [
|
||||
'showitem' => '
|
||||
--palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
|
||||
--palette--;;filePalette',
|
||||
],
|
||||
],
|
||||
],
|
||||
'maxitems' => 1,
|
||||
'minitems' => 1,
|
||||
],
|
||||
$GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']
|
||||
),
|
||||
],
|
||||
'travel_code' => [
|
||||
'exclude' => false,
|
||||
'label' => 'Reisecode',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'size' => 30,
|
||||
'eval' => 'trim,required'
|
||||
],
|
||||
],
|
||||
'hide_address' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'Adresse ausblenden',
|
||||
'config' => [
|
||||
'type' => 'check',
|
||||
],
|
||||
],
|
||||
'intro_text' => [
|
||||
'exclude' => false,
|
||||
'label' => 'Introtext',
|
||||
'config' => [
|
||||
'type' => 'text',
|
||||
'cols' => 40,
|
||||
'rows' => 3,
|
||||
'eval' => 'trim,required',
|
||||
'enableRichtext' => true,
|
||||
]
|
||||
],
|
||||
'bus_info_text' => [
|
||||
'exclude' => false,
|
||||
'label' => 'Businfo',
|
||||
'config' => [
|
||||
'type' => 'text',
|
||||
'cols' => 40,
|
||||
'rows' => 3,
|
||||
'eval' => 'trim',
|
||||
'enableRichtext' => true,
|
||||
]
|
||||
],
|
||||
'departure_text' => [
|
||||
'exclude' => false,
|
||||
'label' => 'Abreise',
|
||||
'config' => [
|
||||
'type' => 'text',
|
||||
'cols' => 40,
|
||||
'rows' => 3,
|
||||
'eval' => 'trim',
|
||||
'enableRichtext' => true,
|
||||
]
|
||||
],
|
||||
'footer_text' => [
|
||||
'exclude' => false,
|
||||
'label' => 'Footertext',
|
||||
'config' => [
|
||||
'type' => 'text',
|
||||
'cols' => 40,
|
||||
'rows' => 3,
|
||||
'eval' => 'trim,required',
|
||||
'enableRichtext' => true,
|
||||
]
|
||||
],
|
||||
'self_arranged_text' => [
|
||||
'exclude' => false,
|
||||
'label' => 'Eigenanreise',
|
||||
'config' => [
|
||||
'type' => 'text',
|
||||
'cols' => 40,
|
||||
'rows' => 15,
|
||||
'eval' => 'trim',
|
||||
'enableRichtext' => true,
|
||||
]
|
||||
],
|
||||
'additional_info' => [
|
||||
'exclude' => false,
|
||||
'label' => 'Weitere Infos',
|
||||
'config' => [
|
||||
'type' => 'text',
|
||||
'cols' => 40,
|
||||
'rows' => 15,
|
||||
'eval' => 'trim',
|
||||
'enableRichtext' => true,
|
||||
]
|
||||
],
|
||||
'important_phone_numbers' => [
|
||||
'exclude' => false,
|
||||
'label' => 'Wichtige Telefonnummern',
|
||||
'config' => [
|
||||
'type' => 'text',
|
||||
'cols' => 40,
|
||||
'rows' => 15,
|
||||
'eval' => 'trim',
|
||||
'enableRichtext' => true,
|
||||
]
|
||||
],
|
||||
'important_links' => [
|
||||
'exclude' => false,
|
||||
'label' => 'Wichtige Links',
|
||||
'config' => [
|
||||
'type' => 'text',
|
||||
'cols' => 40,
|
||||
'rows' => 15,
|
||||
'eval' => 'trim',
|
||||
'enableRichtext' => true,
|
||||
]
|
||||
],
|
||||
'teasers' => [
|
||||
'exclude' => false,
|
||||
'label' => 'Inhalte',
|
||||
'config' => [
|
||||
'type' => 'inline',
|
||||
'foreign_table' => 'tx_epproducts_domain_model_travelinfoteaser',
|
||||
'foreign_sortby' => 'sorting',
|
||||
'foreign_field' => 'tx_epproducts_travelinfo',
|
||||
'minitems' => 0,
|
||||
'maxitems' => 99,
|
||||
'appearance' => [
|
||||
'collapseAll' => true,
|
||||
'expandSingle' => true,
|
||||
'levelLinksPosition' => 'bottom',
|
||||
'useSortable' => true,
|
||||
'showPossibleLocalizationRecords' => false,
|
||||
'showRemovedLocalizationRecords' => false,
|
||||
'showAllLocalizationLink' => false,
|
||||
'showSynchronizationLink' => false,
|
||||
'enabledControls' => [
|
||||
'info' => false,
|
||||
],
|
||||
],
|
||||
'behaviour' => [
|
||||
'allowLanguageSynchronization' => false,
|
||||
],
|
||||
]
|
||||
],
|
||||
'links' => [
|
||||
'exclude' => false,
|
||||
'label' => 'Links',
|
||||
'config' => [
|
||||
'type' => 'inline',
|
||||
'foreign_table' => 'tx_epproducts_domain_model_travelinfolink',
|
||||
'foreign_sortby' => 'sorting',
|
||||
'foreign_field' => 'tx_epproducts_travelinfo',
|
||||
'minitems' => 0,
|
||||
'maxitems' => 3,
|
||||
'appearance' => [
|
||||
'collapseAll' => true,
|
||||
'expandSingle' => true,
|
||||
'levelLinksPosition' => 'bottom',
|
||||
'useSortable' => true,
|
||||
'showPossibleLocalizationRecords' => false,
|
||||
'showRemovedLocalizationRecords' => false,
|
||||
'showAllLocalizationLink' => false,
|
||||
'showSynchronizationLink' => false,
|
||||
'enabledControls' => [
|
||||
'info' => false,
|
||||
],
|
||||
],
|
||||
'behaviour' => [
|
||||
'allowLanguageSynchronization' => false,
|
||||
],
|
||||
]
|
||||
],
|
||||
'path_segment' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'URL',
|
||||
'config' => [
|
||||
'type' => 'slug',
|
||||
'generatorOptions' => [
|
||||
'fields' => ['title'],
|
||||
'prefixParentPageSlug' => false,
|
||||
'replacements' => [
|
||||
'/' => '-',
|
||||
],
|
||||
],
|
||||
'fallbackCharacter' => '-',
|
||||
'eval' => 'unique',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
@@ -1,167 +0,0 @@
|
||||
<?php
|
||||
return [
|
||||
'ctrl' => [
|
||||
'title' => 'Reiseinfo Link',
|
||||
'label' => 'title',
|
||||
'prependAtCopy' => '[COPY %s]',
|
||||
'tstamp' => 'tstamp',
|
||||
'crdate' => 'crdate',
|
||||
'cruser_id' => 'cruser_id',
|
||||
'dividers2tabs' => true,
|
||||
'versioningWS' => true,
|
||||
'hideTable' => true,
|
||||
'languageField' => 'sys_language_uid',
|
||||
'transOrigPointerField' => 'l10n_parent',
|
||||
'transOrigDiffSourceField' => 'l10n_diffsource',
|
||||
'delete' => 'deleted',
|
||||
'enablecolumns' => [
|
||||
'disabled' => 'hidden',
|
||||
'starttime' => 'starttime',
|
||||
'endtime' => 'endtime',
|
||||
],
|
||||
'searchFields' => 'title',
|
||||
'iconfile' => 'EXT:ep_theme/Resources/Public/images/icon_ce.svg',
|
||||
],
|
||||
'types' => [
|
||||
'1' => [
|
||||
'showitem' => '--palette--;;basics,link',
|
||||
],
|
||||
],
|
||||
'palettes' => [
|
||||
'basics' => ['showitem' => 'title,icon,hidden'],
|
||||
],
|
||||
'columns' => [
|
||||
|
||||
'sys_language_uid' => [
|
||||
'exclude' => false,
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
|
||||
'config' => [
|
||||
'type' => 'select',
|
||||
'renderType' => 'selectSingle',
|
||||
'foreign_table' => 'sys_language',
|
||||
'foreign_table_where' => 'ORDER BY sys_language.title',
|
||||
'items' => [
|
||||
['LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.allLanguages', -1],
|
||||
['LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.default_value', 0]
|
||||
],
|
||||
'default' => 0,
|
||||
],
|
||||
],
|
||||
'l10n_parent' => [
|
||||
'displayCond' => 'FIELD:sys_language_uid:>:0',
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent',
|
||||
'config' => [
|
||||
'type' => 'select',
|
||||
'default' => 0,
|
||||
'renderType' => 'selectSingle',
|
||||
'items' => [
|
||||
['', 0],
|
||||
],
|
||||
'foreign_table' => 'tx_epproducts_domain_model_travelinfolink',
|
||||
'foreign_table_where' => 'AND tx_epproducts_domain_model_travelinfolink.pid=###CURRENT_PID### AND tx_epproducts_domain_model_travelinfolink.sys_language_uid IN (-1,0)',
|
||||
],
|
||||
],
|
||||
'l10n_diffsource' => [
|
||||
'config' => [
|
||||
'type' => 'passthrough',
|
||||
],
|
||||
],
|
||||
|
||||
't3ver_label' => [
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.versionLabel',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'size' => 30,
|
||||
'max' => 255,
|
||||
]
|
||||
],
|
||||
|
||||
'hidden' => [
|
||||
'exclude' => false,
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.hidden',
|
||||
'config' => [
|
||||
'type' => 'check',
|
||||
],
|
||||
],
|
||||
'starttime' => [
|
||||
'exclude' => false,
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.starttime',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'size' => 13,
|
||||
'eval' => 'datetime',
|
||||
'checkbox' => 0,
|
||||
'default' => 0,
|
||||
'behaviour' => [
|
||||
'allowLanguageSynchronization' => true,
|
||||
],
|
||||
'renderType' => 'inputDateTime',
|
||||
],
|
||||
],
|
||||
'endtime' => [
|
||||
'exclude' => false,
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.endtime',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'size' => 13,
|
||||
'eval' => 'datetime',
|
||||
'checkbox' => 0,
|
||||
'default' => 0,
|
||||
'behaviour' => [
|
||||
'allowLanguageSynchronization' => true,
|
||||
],
|
||||
'renderType' => 'inputDateTime',
|
||||
],
|
||||
],
|
||||
|
||||
'title' => [
|
||||
'exclude' => false,
|
||||
'label' => 'Bezeichnung',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'size' => 30,
|
||||
'eval' => 'trim,required'
|
||||
],
|
||||
],
|
||||
'link' => [
|
||||
'exclude' => false,
|
||||
'label' => 'Link',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'renderType' => 'inputLink',
|
||||
'size' => 30,
|
||||
'eval' => 'trim,required'
|
||||
],
|
||||
],
|
||||
'icon' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'Icon',
|
||||
'config' => [
|
||||
'type' => 'select',
|
||||
'renderType' => 'selectSingle',
|
||||
'items' => [
|
||||
['Anreise', 'travel'],
|
||||
['Skipass', 'skipass'],
|
||||
['Kurse', 'course'],
|
||||
['Verpflegung', 'food'],
|
||||
['Gepäck', 'luggage'],
|
||||
['Lift', 'lift'],
|
||||
['Webcam', 'webcam'],
|
||||
['Wetter', 'weather'],
|
||||
['Wissenswertes', 'chat'],
|
||||
['Währung', 'currency'],
|
||||
],
|
||||
],
|
||||
],
|
||||
'tx_epproducts_travelinfo' => [
|
||||
'config' => [
|
||||
'type' => 'passthrough'
|
||||
]
|
||||
],
|
||||
'sorting' => [
|
||||
'config' => [
|
||||
'type' => 'passthrough'
|
||||
]
|
||||
],
|
||||
],
|
||||
];
|
||||
-220
@@ -1,220 +0,0 @@
|
||||
<?php
|
||||
return [
|
||||
'ctrl' => [
|
||||
'title' => 'Reiseinfo Teaser',
|
||||
'label' => 'title',
|
||||
'prependAtCopy' => '[COPY %s]',
|
||||
'tstamp' => 'tstamp',
|
||||
'crdate' => 'crdate',
|
||||
'cruser_id' => 'cruser_id',
|
||||
'origUid' => 't3_origuid',
|
||||
'dividers2tabs' => true,
|
||||
'versioningWS' => true,
|
||||
'hideTable' => true,
|
||||
'languageField' => 'sys_language_uid',
|
||||
'transOrigPointerField' => 'l10n_parent',
|
||||
'transOrigDiffSourceField' => 'l10n_diffsource',
|
||||
'delete' => 'deleted',
|
||||
'enablecolumns' => [
|
||||
'disabled' => 'hidden',
|
||||
'starttime' => 'starttime',
|
||||
'endtime' => 'endtime',
|
||||
],
|
||||
'searchFields' => 'title',
|
||||
'iconfile' => 'EXT:ep_theme/Resources/Public/images/icon_ce.svg',
|
||||
],
|
||||
'types' => [
|
||||
'1' => [
|
||||
'showitem' => '--palette--;;basics,bodytext,image',
|
||||
],
|
||||
],
|
||||
'palettes' => [
|
||||
'basics' => ['showitem' => 'title,category,hidden'],
|
||||
],
|
||||
'columns' => [
|
||||
|
||||
'sys_language_uid' => [
|
||||
'exclude' => false,
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
|
||||
'config' => [
|
||||
'type' => 'select',
|
||||
'renderType' => 'selectSingle',
|
||||
'foreign_table' => 'sys_language',
|
||||
'foreign_table_where' => 'ORDER BY sys_language.title',
|
||||
'items' => [
|
||||
['LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.allLanguages', -1],
|
||||
['LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.default_value', 0]
|
||||
],
|
||||
'default' => 0,
|
||||
],
|
||||
],
|
||||
'l10n_parent' => [
|
||||
'displayCond' => 'FIELD:sys_language_uid:>:0',
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent',
|
||||
'config' => [
|
||||
'type' => 'select',
|
||||
'default' => 0,
|
||||
'renderType' => 'selectSingle',
|
||||
'items' => [
|
||||
['', 0],
|
||||
],
|
||||
'foreign_table' => 'tx_epproducts_domain_model_travelinfoteaser',
|
||||
'foreign_table_where' => 'AND tx_epproducts_domain_model_travelinfoteaser.pid=###CURRENT_PID### AND tx_epproducts_domain_model_travelinfoteaser.sys_language_uid IN (-1,0)',
|
||||
],
|
||||
],
|
||||
'l10n_diffsource' => [
|
||||
'config' => [
|
||||
'type' => 'passthrough',
|
||||
],
|
||||
],
|
||||
|
||||
't3ver_label' => [
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.versionLabel',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'size' => 30,
|
||||
'max' => 255,
|
||||
]
|
||||
],
|
||||
|
||||
'hidden' => [
|
||||
'exclude' => false,
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.hidden',
|
||||
'config' => [
|
||||
'type' => 'check',
|
||||
],
|
||||
],
|
||||
'starttime' => [
|
||||
'exclude' => false,
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.starttime',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'size' => 13,
|
||||
'eval' => 'datetime',
|
||||
'checkbox' => 0,
|
||||
'default' => 0,
|
||||
'behaviour' => [
|
||||
'allowLanguageSynchronization' => true,
|
||||
],
|
||||
'renderType' => 'inputDateTime',
|
||||
],
|
||||
],
|
||||
'endtime' => [
|
||||
'exclude' => false,
|
||||
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.endtime',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'size' => 13,
|
||||
'eval' => 'datetime',
|
||||
'checkbox' => 0,
|
||||
'default' => 0,
|
||||
'behaviour' => [
|
||||
'allowLanguageSynchronization' => true,
|
||||
],
|
||||
'renderType' => 'inputDateTime',
|
||||
],
|
||||
],
|
||||
|
||||
'title' => [
|
||||
'exclude' => false,
|
||||
'label' => 'Bezeichnung/Überschrift',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'size' => 30,
|
||||
'eval' => 'trim,required'
|
||||
],
|
||||
],
|
||||
'bodytext' => [
|
||||
'exclude' => false,
|
||||
'label' => 'Text',
|
||||
'config' => [
|
||||
'type' => 'text',
|
||||
'cols' => 40,
|
||||
'rows' => 15,
|
||||
'eval' => 'trim,required',
|
||||
'enableRichtext' => true,
|
||||
]
|
||||
],
|
||||
'image' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'Bild',
|
||||
'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig(
|
||||
'image',
|
||||
[
|
||||
'appearance' => [
|
||||
'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference'
|
||||
],
|
||||
'overrideChildTca' => [
|
||||
'types' => [
|
||||
\TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [
|
||||
'showitem' => '
|
||||
--palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
|
||||
--palette--;;filePalette',
|
||||
],
|
||||
],
|
||||
'columns' => [
|
||||
'crop' => [
|
||||
'config' => [
|
||||
'cropVariants' => [
|
||||
'default' => [
|
||||
'title' => 'Alle Geräte',
|
||||
'allowedAspectRatios' => [
|
||||
'teaser' => [
|
||||
'title' => 'quadtratisch',
|
||||
'value' => 1,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'maxitems' => 1,
|
||||
'minitems' => 1,
|
||||
],
|
||||
$GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']
|
||||
),
|
||||
],
|
||||
'category' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'Kategorie/Icon',
|
||||
'config' => [
|
||||
'type' => 'select',
|
||||
'renderType' => 'selectSingle',
|
||||
'items' => [
|
||||
['Anreise', 'travel'],
|
||||
['Auto', 'car'],
|
||||
['Bus', 'bus'],
|
||||
['Gepäck', 'luggage'],
|
||||
['Getränke', 'drinks'],
|
||||
['Kurse', 'course'],
|
||||
['Lift', 'lift'],
|
||||
['Programm', 'program'],
|
||||
['Skipass', 'skipass'],
|
||||
['Verpflegung', 'food'],
|
||||
['Webcam', 'webcam'],
|
||||
['Wetter', 'weather'],
|
||||
['Wissenswertes', 'chat'],
|
||||
['Leihmaterial', 'rental'],
|
||||
['Teilnehmer', 'participants'],
|
||||
['Bett', 'bed'],
|
||||
['Ablauf', 'sequence'],
|
||||
['Partner', 'partner'],
|
||||
],
|
||||
'maxitems' => 1,
|
||||
'minitems' => 1,
|
||||
],
|
||||
],
|
||||
'tx_epproducts_travelinfo' => [
|
||||
'config' => [
|
||||
'type' => 'passthrough'
|
||||
]
|
||||
],
|
||||
'sorting' => [
|
||||
'config' => [
|
||||
'type' => 'passthrough'
|
||||
]
|
||||
],
|
||||
],
|
||||
];
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<xliff version="1.0" xmlns:t3="http://typo3.org/schemas/xliff">
|
||||
<file t3:id="1415814815" source-language="en" datatype="plaintext" original="messages" date="2013-07-04T16:35:47Z" product-name="documentation">
|
||||
<header/>
|
||||
<body>
|
||||
<trans-unit id="mlang_tabs_tab">
|
||||
<source>E&P Funktionen</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="mlang_labels_tabdescr">
|
||||
<source>Produktspezifische Funktionen</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="mlang_labels_tablabel">
|
||||
<source>Produkte</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
@@ -1 +0,0 @@
|
||||
<f:render section="Main" />
|
||||
@@ -1,47 +0,0 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en"
|
||||
xmlns:core="http://typo3.org/ns/TYPO3/CMS/Core/ViewHelpers"
|
||||
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers">
|
||||
|
||||
<f:layout name="Backend"/>
|
||||
|
||||
<f:section name="Main">
|
||||
<h1>E&P Funktionen</h1>
|
||||
<f:flashMessages />
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">BusPro Daten</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
<strong>Letzter Produktdaten-Import: {f:if(condition: productDataUpdatedTimestamp, then: '{productDataUpdatedTimestamp -> f:format.date(format: \'d.m.Y H:i:s\')}', else: '-')}</strong>
|
||||
</p>
|
||||
<p>
|
||||
<strong>Letzter Kontingente-Import: {f:if(condition: contingentsDataUpdatedTimestamp, then: '{contingentsDataUpdatedTimestamp -> f:format.date(format: \'d.m.Y H:i:s\')}', else: '-')}</strong>
|
||||
</p>
|
||||
<p>
|
||||
<strong>Hinweis:</strong> TYPO3 prüft alle 15 Minuten, ob ein XML Upload aus BusPro erfolgt ist (automatisch
|
||||
oder manuell) und führt sofort einen Import durch falls erforderlich.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
<f:link.action action="importSnowReport" class="btn btn-default">
|
||||
<core:icon identifier="actions-refresh"/>
|
||||
Schneehöhen importieren
|
||||
</f:link.action>
|
||||
</p>
|
||||
<p>
|
||||
<f:link.action action="dumpSearchLogEpreisen" class="btn btn-default">
|
||||
<core:icon identifier="actions-document-export-csv"/>
|
||||
Suchschlitz Auswertung EP Reisen (CSV Download)
|
||||
</f:link.action>
|
||||
</p>
|
||||
<p>
|
||||
<f:link.action action="dumpSearchLogEpevents" class="btn btn-default">
|
||||
<core:icon identifier="actions-document-export-csv"/>
|
||||
Suchschlitz Auswertung EP Events (CSV Download)
|
||||
</f:link.action>
|
||||
</p>
|
||||
</f:section>
|
||||
|
||||
</html>
|
||||
@@ -40,42 +40,6 @@ bpnConnectApiTimeout = 5
|
||||
# cat=MyEpAPI; type=int; label=Bpn Connect API max total request duration in seconds (0 = unlimited)
|
||||
bpnConnectApiMaxDuration = 15
|
||||
|
||||
# cat=EpTeamAPI; type=string; label=MyE&P Team base URL (https, e.g. https://team.ep-reisen.de) - receives application form submissions
|
||||
epTeamApiBaseUrl =
|
||||
|
||||
# cat=EpTeamAPI; type=string; label=MyE&P Team application form API key (sent as X-Api-Key)
|
||||
epTeamApiKey =
|
||||
|
||||
# cat=EpTeamAPI; type=int; label=MyE&P Team API inactivity timeout in seconds (0 = PHP default_socket_timeout)
|
||||
epTeamApiTimeout = 5
|
||||
|
||||
# cat=EpTeamAPI; type=int; label=MyE&P Team API max total request duration in seconds (0 = unlimited)
|
||||
epTeamApiMaxDuration = 15
|
||||
|
||||
# cat=SftpImport; type=options[Remote SFTP server=sftp,Local directory (fileadmin/xmlexport)=local,MyE&P API=api]; label=Product/date import source
|
||||
productImportSource = sftp
|
||||
|
||||
# cat=SftpImport; type=string; label=SFTP host for product/date import
|
||||
productImportSftpHost =
|
||||
|
||||
# cat=SftpImport; type=int+; label=SFTP port
|
||||
productImportSftpPort = 22
|
||||
|
||||
# cat=SftpImport; type=string; label=SFTP username
|
||||
productImportSftpUser =
|
||||
|
||||
# cat=SftpImport; type=string; label=SFTP password
|
||||
productImportSftpPassword =
|
||||
|
||||
# cat=SftpImport; type=string; label=Remote directory holding Ziel_*.xml, zustiege.xml and uebertragung.info
|
||||
productImportSftpRemotePath = /
|
||||
|
||||
# cat=SftpImport; type=string; label=Expected SSH host key (optional; "ssh-ed25519 AAAA..." or "SHA256:..."; empty disables the check)
|
||||
productImportSftpHostKey =
|
||||
|
||||
# cat=SftpImport; type=int+; label=SFTP connection timeout in seconds
|
||||
productImportSftpTimeout = 15
|
||||
|
||||
# cat=ContentFeed; type=string; label=API key for the CMS backchannel endpoints used by MyE&P (/api/hotel, /api/product, /api/content/*); sent as X-Api-Key or ?key=. Empty denies every request.
|
||||
cmsApiKey =
|
||||
|
||||
|
||||
@@ -15,35 +15,6 @@ $boot = function () {
|
||||
// Client-side callers pass these parameters in POST bodies, which cHash never inspects.
|
||||
$GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['requireCacheHashPresenceParameters'][] = '^tx_epproducts_ajax';
|
||||
|
||||
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass']['ep_products'] =
|
||||
\EP\EpProducts\Hooks\Tcemain::class;
|
||||
|
||||
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\EP\EpProducts\Task\ImportDatesTask::class] = [
|
||||
'extension' => 'ep_products',
|
||||
'title' => 'EP Reisedaten Import',
|
||||
'description' => 'Importiert Reisedaten aus busProNet',
|
||||
];
|
||||
|
||||
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\EP\EpProducts\Task\ImportContingentsTask::class] = [
|
||||
'extension' => 'ep_products',
|
||||
'title' => 'EP Kontingent Import',
|
||||
'description' => 'Importiert Kontingentdaten aus busProNet',
|
||||
];
|
||||
|
||||
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\EP\EpProducts\Task\ImportSnowreportTask::class] = [
|
||||
'extension' => 'ep_products',
|
||||
'title' => 'EP Schneehöhen Import',
|
||||
'description' => 'Importiert Schneehöhen',
|
||||
];
|
||||
|
||||
$GLOBALS['TYPO3_CONF_VARS']['LOG']['EP']['EpProducts']['Service']['GroupsSwissService']['writerConfiguration'] = [
|
||||
\TYPO3\CMS\Core\Log\LogLevel::INFO => [
|
||||
'TYPO3\\CMS\\Core\\Log\\Writer\\FileWriter' => [
|
||||
'logFile' => \TYPO3\CMS\Core\Core\Environment::getVarPath() . '/log/groups.swiss.log',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$iconRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Imaging\IconRegistry::class);
|
||||
$iconRegistry->registerIcon(
|
||||
'ep-logo',
|
||||
@@ -51,25 +22,6 @@ $boot = function () {
|
||||
['source' => 'EXT:ep_products/Resources/Public/Icons/logo.svg']
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'searchbar',
|
||||
[
|
||||
'Searchbar' => 'index',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'searchresult',
|
||||
[
|
||||
'Search' => 'searchresult,processSearch',
|
||||
],
|
||||
[
|
||||
'Search' => 'searchresult,processSearch',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'product_detail',
|
||||
@@ -94,227 +46,19 @@ $boot = function () {
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'country_detail',
|
||||
[
|
||||
'Country' => 'detail',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'region_teasergroup',
|
||||
[
|
||||
'Region' => 'teasergroup',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'region_detail',
|
||||
[
|
||||
'Region' => 'detail',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'city_teasergroup',
|
||||
[
|
||||
'City' => 'teasergroup',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'city_detail',
|
||||
[
|
||||
'City' => 'detail',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'hotel_teasergroup',
|
||||
[
|
||||
'Hotel' => 'teasergroup',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'hotel_teasergroup_nodate',
|
||||
[
|
||||
'Hotel' => 'dateIndependentTeasergroup',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'hotel_detail',
|
||||
[
|
||||
'Hotel' => 'detail',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'hotel_detail_event',
|
||||
[
|
||||
'Hotel' => 'detailEvent',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'faq',
|
||||
[
|
||||
'Faq' => 'detail',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'concept_teasergroup',
|
||||
[
|
||||
'Concept' => 'teasergroup',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'concept_detail',
|
||||
[
|
||||
'Concept' => 'detail',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'snowreport_list',
|
||||
[
|
||||
'Snowreport' => 'list',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'teammembers',
|
||||
[
|
||||
'Team' => 'list, show',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'newsletter',
|
||||
[
|
||||
'Newsletter' => 'index',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'newsletter_subscription',
|
||||
[
|
||||
'Newsletter' => 'subscriptionForm,subscriptionFormSubmit',
|
||||
],
|
||||
[
|
||||
'Newsletter' => 'subscriptionForm,subscriptionFormSubmit',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'maps',
|
||||
[
|
||||
'Map' => 'general',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'pricetable',
|
||||
[
|
||||
'Pricetable' => 'event',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'reseller',
|
||||
[
|
||||
'Reseller' => 'list,copypaste',
|
||||
],
|
||||
[
|
||||
'Reseller' => 'list,copypaste',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'watchlist',
|
||||
[
|
||||
'Watchlist' => 'list',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'travelinfo',
|
||||
[
|
||||
'Travelinfo' => 'travelInfo,travelCode',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'ajax',
|
||||
[
|
||||
'AjaxSearch' => 'searchresult',
|
||||
'AjaxFilterPanel' => 'index',
|
||||
'AjaxDate' => 'dates',
|
||||
'AjaxContingent' => 'list,rooms',
|
||||
'AjaxTable' => 'datestable,pricetable,pricetableHtml,eventPricetable,daytripRooms',
|
||||
'AjaxCalendar' => 'range,priceConfig,priceCalendar,priceTable',
|
||||
'AjaxWatchlist' => 'list',
|
||||
'AjaxTeaserPopup' => 'concept',
|
||||
],
|
||||
[
|
||||
'AjaxSearch' => 'searchresult',
|
||||
'AjaxFilterPanel' => 'index',
|
||||
'AjaxDate' => 'dates',
|
||||
'AjaxContingent' => 'list,rooms',
|
||||
'AjaxTable' => 'datestable,pricetable,pricetableHtml,eventPricetable,daytripRooms',
|
||||
'AjaxCalendar' => 'range',
|
||||
'AjaxWatchlist' => 'list',
|
||||
'AjaxTeaserPopup' => 'concept',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'ical',
|
||||
[
|
||||
'Ical' => 'contingents',
|
||||
],
|
||||
[
|
||||
'Ical' => 'contingents',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'api',
|
||||
[
|
||||
'Api' => 'product,hotel',
|
||||
]
|
||||
);
|
||||
|
||||
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['tt_content_drawItem']['ep_products'] =
|
||||
\EP\EpProducts\Hooks\PageLayoutView::class;
|
||||
|
||||
$GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludedParameters'][] = '_gl';
|
||||
$GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludedParameters'][] = 'gclid';
|
||||
$GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludedParameters'][] = 'ref';
|
||||
@@ -339,19 +83,6 @@ $boot = function () {
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['teamSlug'] =
|
||||
\EP\EpProducts\Updates\TeamSlugUpdater::class;
|
||||
|
||||
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\TYPO3\CMS\Scheduler\Task\TableGarbageCollectionTask::class]['options']['tables']['tx_epproducts_log'] = [
|
||||
'dateField' => 'time_micro',
|
||||
'expirePeriod' => '180',
|
||||
];
|
||||
|
||||
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\TYPO3\CMS\Scheduler\Task\TableGarbageCollectionTask::class]['options']['tables']['tx_epevents_log'] = [
|
||||
'dateField' => 'time_micro',
|
||||
'expirePeriod' => '180',
|
||||
];
|
||||
};
|
||||
|
||||
$boot();
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
defined('TYPO3_MODE')|| die('Access denied.');
|
||||
|
||||
call_user_func(function () {
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerModule(
|
||||
'EP.EpProducts',
|
||||
'web',
|
||||
'management',
|
||||
'after:list',
|
||||
[
|
||||
'Backend' => 'index, importProducts, importContingents, importSnowReport, dumpSearchLogEpreisen, dumpSearchLogEpevents',
|
||||
],
|
||||
[
|
||||
'access' => 'user,group',
|
||||
'labels' => 'LLL:EXT:ep_products/Resources/Private/Language/locallang_mod.xlf',
|
||||
'icon' => 'EXT:ep_products/Resources/Public/Icons/logo.svg'
|
||||
]
|
||||
);
|
||||
|
||||
});
|
||||
@@ -1,83 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpTheme\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2020 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\EpTheme\Domain\Repository\PageRepository;
|
||||
use TYPO3\CMS\Backend\View\BackendTemplateView;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
class BackendController extends ActionController
|
||||
{
|
||||
/**
|
||||
* Backend Template Container
|
||||
*
|
||||
* @var BackendTemplateView
|
||||
*/
|
||||
protected $defaultViewObjectName = BackendTemplateView::class;
|
||||
|
||||
/**
|
||||
* BackendTemplateContainer
|
||||
*
|
||||
* @var BackendTemplateView
|
||||
*/
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $pageUid;
|
||||
|
||||
/**
|
||||
* @var PageRepository
|
||||
*/
|
||||
protected $pageRepository;
|
||||
|
||||
/**
|
||||
* @param PageRepository $pageRepository
|
||||
*/
|
||||
public function __construct(PageRepository $pageRepository)
|
||||
{
|
||||
$this->pageRepository = $pageRepository;
|
||||
}
|
||||
|
||||
public function initializeAction()
|
||||
{
|
||||
$this->pageUid = (int)GeneralUtility::_GET('id');
|
||||
|
||||
parent::initializeAction();
|
||||
}
|
||||
|
||||
public function listPagesAction()
|
||||
{
|
||||
$pages = $this->pageRepository->findPagesByPid($this->pageUid, true);
|
||||
|
||||
$this->view->assign('pages', $pages);
|
||||
}
|
||||
}
|
||||
Loaded 100 of 331 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user