chore: copy ep_products and ep_theme from EP/website@9593cc8

Copied unchanged from public/typo3conf/ext/ of EP/website at
9593cc8631354f8a363d6609de8b7433f669a9a0 (Git-tracked files only).
History stays in the old repository. Only composer.json files are
added so the extensions install as path packages.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
frommeandClaude Opus 5.5 committed 2026-10-21 14:01:20 +02:00
1 parent 59afaecea1
commit a46918de9d
778 files changed
+67000 -2

No files matched your search

+2
View File
@@ -16,6 +16,8 @@
},
"require": {
"b13/container": "^4.1",
"ep/ep-products": "@dev",
"ep/ep-theme": "@dev",
"ssch/typo3-encore": "^7.0",
"typo3/cms-backend": "^13.4",
"typo3/cms-belog": "^13.4",
Generated
+425 -2
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "d4af0a677424f63a718c41200397902d",
"content-hash": "360f5f33d266a5b828de7280a438b5ce",
"packages": [
{
"name": "b13/container",
@@ -816,6 +816,92 @@
},
"time": "2026-10-20T09:45:10+00:00"
},
{
"name": "ep/ep-products",
"version": "dev-master",
"dist": {
"type": "path",
"url": "./packages/ep_products",
"reference": "291793cfe2a2d5f50bf5bee13f286e501d633a49"
},
"require": {
"league/oauth2-client": "^2.9",
"league/period": "^4.12",
"php": "^8.2",
"symfony/http-client": "^7.4",
"typo3/cms-core": "^13.4",
"typo3/cms-extbase": "^13.4",
"typo3/cms-fluid": "^13.4",
"typo3/cms-frontend": "^13.4"
},
"type": "typo3-cms-extension",
"extra": {
"typo3/cms": {
"extension-key": "ep_products"
}
},
"autoload": {
"psr-4": {
"EP\\EpProducts\\": "Classes/"
}
},
"license": [
"GPL-2.0-or-later"
],
"authors": [
{
"name": "Björn Fromme",
"email": "[email protected]"
}
],
"description": "Implementation of all product related logic and models",
"transport-options": {
"relative": true
}
},
{
"name": "ep/ep-theme",
"version": "dev-master",
"dist": {
"type": "path",
"url": "./packages/ep_theme",
"reference": "f3e425fca030011066b3d2e6a25a756941885b0d"
},
"require": {
"b13/container": "^4.1",
"ep/ep-products": "@dev",
"php": "^8.2",
"typo3/cms-core": "^13.4",
"typo3/cms-extbase": "^13.4",
"typo3/cms-fluid": "^13.4",
"typo3/cms-fluid-styled-content": "^13.4",
"typo3/cms-frontend": "^13.4"
},
"type": "typo3-cms-extension",
"extra": {
"typo3/cms": {
"extension-key": "ep_theme"
}
},
"autoload": {
"psr-4": {
"EP\\EpTheme\\": "Classes/"
}
},
"license": [
"GPL-2.0-or-later"
],
"authors": [
{
"name": "Björn Fromme",
"email": "[email protected]"
}
],
"description": "Theme package for Ep Reisen TYPO3 website",
"transport-options": {
"relative": true
}
},
{
"name": "firebase/php-jwt",
"version": "v7.2.1",
@@ -1219,6 +1305,157 @@
],
"time": "2026-10-17T23:57:19+00:00"
},
{
"name": "league/oauth2-client",
"version": "2.9.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/oauth2-client.git",
"reference": "8cedfef9d01a8d1fd2ecfabb41734b17592c4b71"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/oauth2-client/zipball/8cedfef9d01a8d1fd2ecfabb41734b17592c4b71",
"reference": "8cedfef9d01a8d1fd2ecfabb41734b17592c4b71",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/guzzle": "^6.5.8 || ^7.8.2 || ^8.0",
"guzzlehttp/psr7": "^1.9.1 || ^2.6.3 || ^3.0",
"php": "^7.1 || >=8.0.0 <8.6.0"
},
"require-dev": {
"mockery/mockery": "^1.3.5",
"php-parallel-lint/php-parallel-lint": "^1.4",
"phpunit/phpunit": "^7 || ^8 || ^9 || ^10 || ^11",
"squizlabs/php_codesniffer": "^3.11"
},
"type": "library",
"autoload": {
"psr-4": {
"League\\OAuth2\\Client\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Alex Bilbie",
"email": "[email protected]",
"homepage": "http://www.alexbilbie.com",
"role": "Developer"
},
{
"name": "Woody Gilk",
"homepage": "https://github.com/shadowhand",
"role": "Contributor"
}
],
"description": "OAuth 2.0 Client Library",
"keywords": [
"Authentication",
"SSO",
"authorization",
"identity",
"idp",
"oauth",
"oauth2",
"single sign on"
],
"support": {
"issues": "https://github.com/thephpleague/oauth2-client/issues",
"source": "https://github.com/thephpleague/oauth2-client/tree/2.9.1"
},
"time": "2026-09-16T13:14:31+00:00"
},
{
"name": "league/period",
"version": "4.12.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/period.git",
"reference": "766e9dddabbbef7d9655efd857ce977f8541b596"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/period/zipball/766e9dddabbbef7d9655efd857ce977f8541b596",
"reference": "766e9dddabbbef7d9655efd857ce977f8541b596",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": "^7.2.0 || ^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^v2.19 || ~v3.4.0",
"phpstan/phpstan": "^1.0.0",
"phpstan/phpstan-phpunit": "^1.0.0",
"phpstan/phpstan-strict-rules": "^1.0.0",
"phpunit/phpunit": "^8.0 || ^9.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.x-dev"
}
},
"autoload": {
"files": [
"src/functions_include.php"
],
"psr-4": {
"League\\Period\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ignace Nyamagana Butera",
"email": "[email protected]",
"homepage": "https://github.com/nyamsprod/",
"role": "Developer"
}
],
"description": "Time range API for PHP",
"homepage": "http://period.thephpleague.com",
"keywords": [
"boundaries",
"calendar",
"collection",
"date",
"dateinterval",
"dateperiod",
"datetime",
"gap",
"intersections",
"interval",
"period",
"range",
"schedule",
"sequence",
"time",
"timeline",
"unions"
],
"support": {
"docs": "https://period.thephpleague.com",
"issues": "https://github.com/thephpleague/period/issues",
"source": "https://github.com/thephpleague/period"
},
"funding": [
{
"url": "https://github.com/sponsors/nyamsprod",
"type": "github"
}
],
"time": "2022-02-21T08:41:21+00:00"
},
{
"name": "lolli42/finediff",
"version": "1.1.2",
@@ -3420,6 +3657,189 @@
],
"time": "2026-09-26T06:31:10+00:00"
},
{
"name": "symfony/http-client",
"version": "v7.4.21",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client.git",
"reference": "121bf3a973bfd852db85ec32d0d64e9fbed4449b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-client/zipball/121bf3a973bfd852db85ec32d0d64e9fbed4449b",
"reference": "121bf3a973bfd852db85ec32d0d64e9fbed4449b",
"shasum": ""
},
"require": {
"php": ">=8.2",
"psr/log": "^1|^2|^3",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/http-client-contracts": "~3.4.4|^3.5.2",
"symfony/polyfill-php83": "^1.29",
"symfony/service-contracts": "^2.5|^3"
},
"conflict": {
"amphp/amp": "<2.5",
"amphp/socket": "<1.1",
"php-http/discovery": "<1.15",
"symfony/http-foundation": "<6.4"
},
"provide": {
"php-http/async-client-implementation": "*",
"php-http/client-implementation": "*",
"psr/http-client-implementation": "1.0",
"symfony/http-client-implementation": "3.0"
},
"require-dev": {
"amphp/http-client": "^4.2.1|^5.0",
"amphp/http-tunnel": "^1.0|^2.0",
"guzzlehttp/promises": "^1.4|^2.0",
"nyholm/psr7": "^1.0",
"php-http/httplug": "^1.0|^2.0",
"psr/http-client": "^1.0",
"symfony/amphp-http-client-meta": "^1.0|^2.0",
"symfony/cache": "^6.4|^7.0|^8.0",
"symfony/dependency-injection": "^6.4|^7.0|^8.0",
"symfony/http-kernel": "^6.4|^7.0|^8.0",
"symfony/messenger": "^6.4|^7.0|^8.0",
"symfony/process": "^6.4|^7.0|^8.0",
"symfony/rate-limiter": "^6.4|^7.0|^8.0",
"symfony/stopwatch": "^6.4|^7.0|^8.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\HttpClient\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously",
"homepage": "https://symfony.com",
"keywords": [
"http"
],
"support": {
"source": "https://github.com/symfony/http-client/tree/v7.4.21"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2026-10-13T15:31:38+00:00"
},
{
"name": "symfony/http-client-contracts",
"version": "v3.7.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client-contracts.git",
"reference": "35be0019e2c2c9fba80f9dc033290a5240f7b44f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/35be0019e2c2c9fba80f9dc033290a5240f7b44f",
"reference": "35be0019e2c2c9fba80f9dc033290a5240f7b44f",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.7-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\HttpClient\\": ""
},
"exclude-from-classmap": [
"/Test/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Generic abstractions related to HTTP clients",
"homepage": "https://symfony.com",
"keywords": [
"abstractions",
"contracts",
"decoupling",
"interfaces",
"interoperability",
"standards"
],
"support": {
"source": "https://github.com/symfony/http-client-contracts/tree/v3.7.3"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2026-08-04T08:41:16+00:00"
},
{
"name": "symfony/http-foundation",
"version": "v7.4.21",
@@ -9409,7 +9829,10 @@
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {},
"stability-flags": {
"ep/ep-products": 20,
"ep/ep-theme": 20
},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {},
@@ -0,0 +1,140 @@
<?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;
}
}
@@ -0,0 +1,7 @@
<?php
namespace EP\EpProducts\BpnConnect;
class ApiException extends \RuntimeException
{
}
@@ -0,0 +1,75 @@
<?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;
}
}
@@ -0,0 +1,120 @@
<?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\DateImportService;
use EP\EpProducts\Service\ProductImportSourceFactory;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Extbase\Service\CacheService;
class DateCommandController extends Command
{
/**
* @var \EP\EpProducts\Service\DateImportService
*/
protected $dateImportService;
/**
* @var CacheService
*/
protected $cacheService;
/**
* @var ConfigurationManagerInterface
*/
protected $configurationManager;
/**
* @var ProductImportSourceFactory
*/
protected $importSourceFactory;
/**
* @param DateImportService $importService
* @param CacheService $cacheService
* @param ConfigurationManagerInterface $configurationManager
* @param ProductImportSourceFactory $importSourceFactory
*/
public function __construct
(
DateImportService $importService,
CacheService $cacheService,
ConfigurationManagerInterface $configurationManager,
ProductImportSourceFactory $importSourceFactory
)
{
$this->dateImportService = $importService;
$this->cacheService = $cacheService;
$this->configurationManager = $configurationManager;
$this->importSourceFactory = $importSourceFactory;
parent::__construct();
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @throws \Doctrine\DBAL\DBALException
*/
public function execute(InputInterface $input, OutputInterface $output): int
{
$importSource = $this->importSourceFactory->get();
$import = $importSource->acquire();
if ($import === null) {
$output->writeln('No new import available.');
return 0;
}
$count = $this->dateImportService->import($import->getRows());
$importSource->markImported($import);
$output->writeln(sprintf('%d rows imported.', $count ));
$settings = $this->getSettings();
$resellerPageUid = $settings['resellerExportPageUid'];
$travelInfoPageUid = $settings['travelInfoPageUid'];
$this->cacheService->clearPageCache([$resellerPageUid, $travelInfoPageUid]);
return 0;
}
/**
* @return array
*/
protected function getSettings(): array
{
$settings = $this
->configurationManager
->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT);
return $settings['plugin.']['tx_epproducts.']['settings.'];
}
}
@@ -0,0 +1,178 @@
<?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';
}
}
@@ -0,0 +1,85 @@
<?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;
}
}
@@ -0,0 +1,62 @@
<?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;
}
}
@@ -0,0 +1,165 @@
<?php
namespace EP\EpProducts\ContentFeed;
use EP\EpProducts\Http\ApiKeyAuthenticator;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Cache\CacheManager;
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
use TYPO3\CMS\Core\Http\JsonResponse;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* The chatbot content feed's backchannel endpoints under /api/content/.
*
* See .ddev/plans/CHATBOT-MCP-01-TYPO3-CONTENT-FEED.md.
*/
class ContentFeedApi
{
public const PATH_PREFIX = '/api/content/';
private const MANIFEST_CACHE_IDENTIFIER = 'content_feed_manifest';
// The consumer polls every 15 minutes, so this caps the build at once per poll however
// often it retries. Edits reach the chatbot within about 25 minutes.
private const MANIFEST_CACHE_LIFETIME = 600;
private const MAX_RECORDS_PER_REQUEST = 100;
private const DISABLED_RETRY_AFTER = 3600;
private const JSON_FLAGS = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES;
/**
* @var ApiKeyAuthenticator
*/
private $authenticator;
/**
* @var ContentFeedConfiguration
*/
private $configuration;
/**
* @var ManifestBuilder
*/
private $manifestBuilder;
/**
* @var RecordSerializer
*/
private $recordSerializer;
/**
* @var FrontendInterface
*/
private $cache;
public function __construct(
ApiKeyAuthenticator $authenticator,
ContentFeedConfiguration $configuration,
ManifestBuilder $manifestBuilder,
RecordSerializer $recordSerializer,
CacheManager $cacheManager
) {
$this->authenticator = $authenticator;
$this->configuration = $configuration;
$this->manifestBuilder = $manifestBuilder;
$this->recordSerializer = $recordSerializer;
$this->cache = $cacheManager->getCache('ep_products_cache');
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
if (!$this->authenticator->isAuthorized($request)) {
return $this->error('Invalid or missing api key', 403);
}
if (!$this->configuration->isEnabled()) {
return self::disabledResponse();
}
if ([] === $this->configuration->getSites()) {
// An empty feed would read as "everything was deleted". Refuse instead.
return $this->error('Content feed has no sites configured', 503);
}
$path = substr($request->getUri()->getPath(), strlen(self::PATH_PREFIX));
if ('manifest' === $path) {
return new JsonResponse($this->getManifest(), 200, [], self::JSON_FLAGS);
}
if ('records' === $path) {
return $this->handleRecordsRequest($request);
}
return $this->error('Not found', 404);
}
/**
* Uids that are not (or no longer) eligible are left out rather than answered with an error:
* the manifest may have changed between the consumer's two calls, and it reads a requested
* but absent uid as deleted.
*/
private function handleRecordsRequest(ServerRequestInterface $request): ResponseInterface
{
$type = (string) ($request->getQueryParams()['type'] ?? '');
if (!isset(RecordFinder::TYPES[$type])) {
return $this->error('Unknown type, expected one of: ' . implode(', ', array_keys(RecordFinder::TYPES)), 400);
}
$uids = array_values(array_unique(array_filter(
GeneralUtility::intExplode(',', (string) ($request->getQueryParams()['uids'] ?? ''), true),
function (int $uid): bool {
return $uid > 0;
}
)));
if ([] === $uids) {
return $this->error('No uids given', 400);
}
if (count($uids) > self::MAX_RECORDS_PER_REQUEST) {
return $this->error(sprintf('At most %d uids per request', self::MAX_RECORDS_PER_REQUEST), 400);
}
return new JsonResponse([
'type' => $type,
'items' => $this->recordSerializer->serialize($type, $uids),
], 200, [], self::JSON_FLAGS);
}
private function getManifest(): array
{
$manifest = $this->cache->get(self::MANIFEST_CACHE_IDENTIFIER);
if (!is_array($manifest)) {
$manifest = $this->manifestBuilder->build();
$this->cache->set(self::MANIFEST_CACHE_IDENTIFIER, $manifest, [], self::MANIFEST_CACHE_LIFETIME);
}
return $manifest;
}
/**
* The kill switch: contentFeedEnabled = 0 in the extension configuration, for when the host
* is struggling. The consumer stops its run, keeps everything it has and tries again later -
* nothing is deleted on the chatbot side.
*/
public static function disabledResponse(): ResponseInterface
{
return new JsonResponse(
['message' => 'Content feed is switched off'],
503,
['Retry-After' => (string) self::DISABLED_RETRY_AFTER],
self::JSON_FLAGS
);
}
private function error(string $message, int $status): ResponseInterface
{
return new JsonResponse(['message' => $message], $status, [], self::JSON_FLAGS);
}
}
@@ -0,0 +1,75 @@
<?php
namespace EP\EpProducts\ContentFeed;
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* The chatbot content feed's extension configuration.
*
* Missing keys fall back to "feed is on, but covers nothing": a key added to ext_conf_template.txt
* is absent until the extension configuration is saved in the backend, and an empty feed is
* refused by the consumer rather than read as "everything was deleted".
*/
class ContentFeedConfiguration
{
/**
* @var array
*/
private $configuration;
public function __construct(ExtensionConfiguration $extensionConfiguration)
{
$this->configuration = (array) $extensionConfiguration->get('ep_products');
}
public function isEnabled(): bool
{
return (bool) ($this->configuration['contentFeedEnabled'] ?? true);
}
/**
* @return string[] site identifiers
*/
public function getSites(): array
{
return GeneralUtility::trimExplode(',', (string) ($this->configuration['contentFeedSites'] ?? ''), true);
}
/**
* @return int[] language ids; the default language when unset
*/
public function getLanguages(): array
{
$languages = GeneralUtility::intExplode(',', (string) ($this->configuration['contentFeedLanguages'] ?? '0'), true);
return [] === $languages ? [0] : $languages;
}
/**
* @return int[] page uids whose whole subtree stays out of the feed
*/
public function getExcludedPages(): array
{
return GeneralUtility::intExplode(',', (string) ($this->configuration['contentFeedExcludedPages'] ?? ''), true);
}
/**
* @return array<string, int> site identifier => news detail page uid
*/
public function getNewsDetailPages(): array
{
$pages = [];
foreach (GeneralUtility::trimExplode(',', (string) ($this->configuration['contentFeedNewsDetailPages'] ?? ''), true) as $entry) {
$parts = GeneralUtility::trimExplode(':', $entry, true);
if (2 === count($parts) && (int) $parts[1] > 0) {
$pages[$parts[0]] = (int) $parts[1];
}
}
return $pages;
}
}
@@ -0,0 +1,379 @@
<?php
namespace EP\EpProducts\ContentFeed;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Site\Entity\Site;
/**
* Builds GET /api/content/manifest: everything the content feed publishes, with a modification
* marker per item and no bodies. The list is complete - an item missing from it is gone - so the
* consumer never has to infer deletions from timestamps.
*
* See .ddev/plans/CHATBOT-MCP-01-TYPO3-CONTENT-FEED.md §4.
*/
class ManifestBuilder
{
public const CONTENT_PAGE_TYPE = 1730;
private const DOKTYPE_DEFAULT = 1;
// Recycler and backend user section: nothing below them is public.
private const DOKTYPES_NOT_TRAVERSED = [6, 255];
// l18n_cfg bit 1: "hide default translation of page".
private const L18N_HIDE_DEFAULT_LANGUAGE = 1;
private const RECORD_FIELDS = [
'product' => ['uid', 'tstamp', 'detail_page'],
'hotel' => ['uid', 'tstamp', 'detail_page'],
'region' => ['uid', 'tstamp', 'detail_page'],
'country' => ['uid', 'tstamp', 'detail_page'],
'city' => ['uid', 'tstamp', 'detail_page'],
'concept' => ['uid', 'tstamp', 'detail_page'],
'news' => ['uid', 'tstamp', 'pid'],
];
/**
* @var PageTree
*/
private $pageTree;
/**
* @var UrlResolver
*/
private $urlResolver;
/**
* @var RecordFinder
*/
private $recordFinder;
/**
* @var ContentFeedConfiguration
*/
private $configuration;
/**
* @var ConnectionPool
*/
private $connectionPool;
public function __construct(
PageTree $pageTree,
UrlResolver $urlResolver,
RecordFinder $recordFinder,
ContentFeedConfiguration $configuration,
ConnectionPool $connectionPool
) {
$this->pageTree = $pageTree;
$this->urlResolver = $urlResolver;
$this->recordFinder = $recordFinder;
$this->configuration = $configuration;
$this->connectionPool = $connectionPool;
}
public function build(): array
{
$sites = $this->urlResolver->getIncludedSites();
$records = $this->buildRecordItems();
return [
'generatedAt' => date('c'),
'sites' => array_map([$this, 'describeSite'], $sites),
'items' => array_merge($this->buildPageItems($sites, $this->collectDetailPages()), $records),
];
}
private function describeSite(Site $site): array
{
$languages = [];
foreach ($site->getLanguages() as $language) {
$languages[] = $language->getTwoLetterIsoCode();
}
$title = trim((string) ($site->getConfiguration()['websiteTitle'] ?? ''));
if ('' === $title) {
$title = trim($site->getDefaultLanguage()->getWebsiteTitle());
}
return [
'identifier' => $site->getIdentifier(),
'title' => '' !== $title ? $title : $site->getIdentifier(),
'base' => (string) $site->getBase(),
'languages' => $languages,
];
}
/**
* @param Site[] $sites
* @param array<int, array> $detailPages detailOf entries by page uid
*/
private function buildPageItems(array $sites, array $detailPages): array
{
$content = $this->findContentStatistics();
$excluded = array_flip($this->configuration->getExcludedPages());
$feedLanguages = $this->configuration->getLanguages();
$items = [];
foreach ($sites as $site) {
$languageIds = [];
foreach ($site->getLanguages() as $language) {
if (in_array($language->getLanguageId(), $feedLanguages, true)) {
$languageIds[$language->getLanguageId()] = $language->getTwoLetterIsoCode();
}
}
$context = [
'site' => $site,
'languages' => $languageIds,
'excluded' => $excluded,
'content' => $content,
'detailPages' => $detailPages,
];
$breadcrumbs = array_fill_keys(array_keys($languageIds), []);
$this->walk($site->getRootPageId(), $context, $breadcrumbs, true, $items);
}
return $items;
}
/**
* @param array<int, string[]> $breadcrumbs titles above this page, by language id
*/
private function walk(int $uid, array $context, array $breadcrumbs, bool $isRoot, array &$items): void
{
$page = $this->pageTree->getPage($uid);
if (null === $page || isset($context['excluded'][$uid])) {
return;
}
if (in_array((int) $page['doktype'], self::DOKTYPES_NOT_TRAVERSED, true)) {
return;
}
$visible = $this->pageTree->isVisible($page);
if (!$visible && (int) $page['extendToSubpages'] === 1) {
return;
}
$childBreadcrumbs = $breadcrumbs;
foreach ($context['languages'] as $languageId => $isoCode) {
$row = $this->getLanguageRow($page, $languageId);
if ($visible && null !== $row && $this->isPublishable($page, $row, $languageId)) {
$item = $this->buildPageItem($page, $row, $languageId, $isoCode, $breadcrumbs[$languageId], $context);
if (null !== $item) {
$items[] = $item;
}
}
if (!$isRoot) {
$source = $row ?? $page;
$childBreadcrumbs[$languageId][] = '' !== trim((string) $source['nav_title'])
? trim((string) $source['nav_title'])
: trim((string) $source['title']);
}
}
foreach ($this->pageTree->getChildren($uid) as $childUid) {
$this->walk($childUid, $context, $childBreadcrumbs, false, $items);
}
}
private function getLanguageRow(array $page, int $languageId): ?array
{
if (0 === $languageId) {
return $page;
}
$overlay = $this->pageTree->getOverlay((int) $page['uid'], $languageId);
return null !== $overlay && $this->pageTree->isVisible($overlay) ? $overlay : null;
}
/**
* Mirrors the XML sitemap: standard pages only, nothing marked no_index. If Google is not
* meant to see a page, the chatbot is not either.
*/
private function isPublishable(array $page, array $row, int $languageId): bool
{
if ((int) $page['doktype'] !== self::DOKTYPE_DEFAULT || (int) $row['no_index'] === 1) {
return false;
}
return 0 !== $languageId || 0 === ((int) $page['l18n_cfg'] & self::L18N_HIDE_DEFAULT_LANGUAGE);
}
private function buildPageItem(array $page, array $row, int $languageId, string $isoCode, array $breadcrumb, array $context): ?array
{
$uid = (int) $page['uid'];
// "Show content from page": the elements live on another page, and so do their changes.
// The site answers 404 when that page is hidden.
$contentPid = (int) $page['content_from_pid'] ?: $uid;
$contentPage = $this->pageTree->getPage($contentPid);
if (null === $contentPage || !$this->pageTree->isVisible($contentPage)) {
return null;
}
// Without a visible element other than plugins, the content-only render is empty (it
// leaves plugins out), so there is nothing to fetch. That is most product and hotel
// detail pages: their text comes through the records endpoint.
$content = $context['content'][$contentPid] ?? [];
$textElements = ($content[$languageId]['text'] ?? 0) + ($content[-1]['text'] ?? 0);
if (0 === $textElements) {
return null;
}
$url = $this->urlResolver->getPageUrl($uid, $languageId);
if (null === $url) {
return null;
}
$modified = max(
(int) $row['tstamp'],
$content[$languageId]['tstamp'] ?? 0,
$content[-1]['tstamp'] ?? 0
);
return [
'type' => 'page',
'uid' => $uid,
'language' => $isoCode,
'site' => $context['site']->getIdentifier(),
'url' => $url,
'contentUrl' => $this->urlResolver->getPageUrl($uid, $languageId, ['type' => self::CONTENT_PAGE_TYPE]),
'title' => trim((string) $row['title']),
'description' => $this->nullIfEmpty((string) $row['description']),
'breadcrumb' => $breadcrumb,
'detailOf' => $context['detailPages'][$uid] ?? [],
'modified' => date('c', $modified),
];
}
/**
* Per page and language: the latest change to any content element, and how many visible
* elements are not plugins.
* Deleted and hidden elements count towards the change - removing or hiding one changes the
* page - which is also why SYS_LASTCHANGED is no use here: it only moves on render.
*
* @return array<int, array<int, array{tstamp: int, text: int}>>
*/
private function findContentStatistics(): array
{
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('tt_content');
$queryBuilder->getRestrictions()->removeAll();
$rows = $queryBuilder
->selectLiteral(
'pid',
'sys_language_uid',
'MAX(tstamp) AS tstamp',
"SUM(CASE WHEN deleted = 0 AND hidden = 0 AND CType <> 'list' THEN 1 ELSE 0 END) AS text_elements"
)
->from('tt_content')
->groupBy('pid', 'sys_language_uid')
->execute()
->fetchAllAssociative()
;
$statistics = [];
foreach ($rows as $row) {
$statistics[(int) $row['pid']][(int) $row['sys_language_uid']] = [
'tstamp' => (int) $row['tstamp'],
'text' => (int) $row['text_elements'],
];
}
return $statistics;
}
/**
* Which records name a page as their detail page. Keyed by the page the record points at,
* not by where a shortcut leads: a shortcut is not in the manifest, and the page it leads to
* usually describes something broader (product detail shortcuts point at region pages).
*
* @return array<int, array>
*/
private function collectDetailPages(): array
{
$detailPages = [];
foreach (self::RECORD_FIELDS as $type => $fields) {
if (!in_array('detail_page', $fields, true)) {
continue;
}
foreach ($this->recordFinder->find($type, ['uid', 'detail_page']) as $uid => $row) {
$pageUid = $this->urlResolver->parsePageReference((string) $row['detail_page']);
if (null !== $pageUid) {
$detailPages[$pageUid][] = ['type' => $type, 'uid' => $uid];
}
}
}
return $detailPages;
}
private function buildRecordItems(): array
{
$faqTimestamps = $this->recordFinder->findFaqTimestamps();
$matchcodeTimestamps = $this->recordFinder->findMatchcodeTimestamps();
$items = [];
foreach (self::RECORD_FIELDS as $type => $fields) {
foreach ($this->recordFinder->find($type, $fields) as $uid => $row) {
if ('news' === $type) {
$link = $this->urlResolver->getNewsLink((int) $row['uid'], (int) $row['pid']);
// News has no detail_page of its own: an article stored outside the feed's
// sites (the retired ep-events) is not part of the feed at all.
if (null === $link) {
continue;
}
} else {
$link = $this->urlResolver->getRecordLink((string) $row['detail_page']);
}
$modified = (int) $row['tstamp'];
if ('product' === $type) {
$modified = max($modified, $faqTimestamps[$uid] ?? 0);
}
if ('hotel' === $type) {
$modified = max($modified, $matchcodeTimestamps[$uid] ?? 0);
}
$items[] = [
'type' => $type,
'uid' => $uid,
'language' => 'de',
'site' => $link['site'],
'url' => $link['url'],
'modified' => date('c', $modified),
];
}
}
return $items;
}
private function nullIfEmpty(string $value): ?string
{
$value = trim($value);
return '' === $value ? null : $value;
}
}
@@ -0,0 +1,131 @@
<?php
namespace EP\EpProducts\ContentFeed;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
/**
* The whole page table in memory, for the content feed's tree walk and shortcut resolution.
*
* About 2 900 rows: one query and a PHP walk is far cheaper than a query per tree level.
* Visibility is evaluated here, not in SQL, because a hidden page still has to be traversed
* (its subpages stay reachable unless extendToSubpages is set).
*/
class PageTree
{
private const FIELDS = [
'uid', 'pid', 'sorting', 'doktype', 'hidden', 'starttime', 'endtime', 'fe_group',
'extendToSubpages', 'no_index', 'title', 'nav_title', 'description', 'shortcut',
'shortcut_mode', 'content_from_pid', 'tstamp', 'sys_language_uid', 'l10n_parent', 'l18n_cfg',
];
/**
* @var ConnectionPool
*/
private $connectionPool;
/**
* @var int
*/
private $now;
/**
* @var array<int, array>|null default-language rows by uid
*/
private $pages;
/**
* @var array<int, int[]> child uids by parent uid, in sorting order
*/
private $children = [];
/**
* @var array<int, array<int, array>> overlay rows by default-language uid and language id
*/
private $overlays = [];
public function __construct(ConnectionPool $connectionPool, Context $context)
{
$this->connectionPool = $connectionPool;
$this->now = (int) $context->getPropertyFromAspect('date', 'timestamp');
}
public function getPage(int $uid): ?array
{
$this->load();
return $this->pages[$uid] ?? null;
}
public function getOverlay(int $uid, int $languageId): ?array
{
$this->load();
return $this->overlays[$uid][$languageId] ?? null;
}
/**
* @return int[]
*/
public function getChildren(int $uid): array
{
$this->load();
return $this->children[$uid] ?? [];
}
/**
* Visible to an anonymous frontend visitor: not hidden, inside its start/end window, and not
* restricted to a frontend user group.
*/
public function isVisible(array $row): bool
{
if ((int) $row['hidden'] === 1) {
return false;
}
if ((int) $row['starttime'] > $this->now) {
return false;
}
if ((int) $row['endtime'] !== 0 && (int) $row['endtime'] <= $this->now) {
return false;
}
return in_array((string) $row['fe_group'], ['', '0'], true);
}
private function load(): void
{
if (null !== $this->pages) {
return;
}
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('pages');
$queryBuilder->getRestrictions()->removeAll()->add(new DeletedRestriction());
$rows = $queryBuilder
->select(...self::FIELDS)
->from('pages')
->orderBy('sorting')
->execute()
->fetchAllAssociative()
;
$this->pages = [];
foreach ($rows as $row) {
$uid = (int) $row['uid'];
if ((int) $row['sys_language_uid'] > 0) {
$this->overlays[(int) $row['l10n_parent']][(int) $row['sys_language_uid']] = $row;
continue;
}
$this->pages[$uid] = $row;
$this->children[(int) $row['pid']][] = $uid;
}
}
}
@@ -0,0 +1,152 @@
<?php
namespace EP\EpProducts\ContentFeed;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
/**
* Which records the content feed publishes. The manifest and the records endpoint both go
* through here, so a uid the manifest lists is exactly a uid the records endpoint returns.
*
* The default restrictions apply: deleted, hidden, starttime and endtime.
*/
class RecordFinder
{
public const TYPES = [
'product' => 'tx_epproducts_domain_model_product',
'hotel' => 'tx_epproducts_domain_model_hotel',
'region' => 'tx_epproducts_domain_model_region',
'country' => 'tx_epproducts_domain_model_country',
'city' => 'tx_epproducts_domain_model_city',
'concept' => 'tx_epproducts_domain_model_concept',
'news' => 'tx_news_domain_model_news',
];
/**
* @var ConnectionPool
*/
private $connectionPool;
public function __construct(ConnectionPool $connectionPool)
{
$this->connectionPool = $connectionPool;
}
/**
* @param string[] $fields
* @param int[]|null $uids null for all eligible records
* @return array<int, array> rows by uid, in uid order
*/
public function find(string $type, array $fields, ?array $uids = null): array
{
$table = self::TYPES[$type];
$queryBuilder = $this->connectionPool->getQueryBuilderForTable($table);
$queryBuilder
->select(...$fields)
->from($table)
->where($queryBuilder->expr()->in('sys_language_uid', [0, -1]))
->orderBy('uid')
;
if (null !== $uids) {
if ([] === $uids) {
return [];
}
$queryBuilder->andWhere($queryBuilder->expr()->in(
'uid',
$queryBuilder->createNamedParameter($uids, Connection::PARAM_INT_ARRAY)
));
}
$this->addTypeConstraints($type, $queryBuilder);
$rows = [];
foreach ($queryBuilder->execute()->fetchAllAssociative() as $row) {
$rows[(int) $row['uid']] = $row;
}
return $rows;
}
/**
* Latest change to a product's FAQs, by product uid. Deleted and hidden FAQs count: removing
* one is a change to the product's text.
*
* @return array<int, int>
*/
public function findFaqTimestamps(): array
{
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('tx_epproducts_domain_model_faq');
$queryBuilder->getRestrictions()->removeAll();
$rows = $queryBuilder
->selectLiteral('mm.uid_local AS product', 'MAX(faq.tstamp) AS tstamp')
->from('tx_epproducts_product_faq_mm', 'mm')
->join('mm', 'tx_epproducts_domain_model_faq', 'faq', 'faq.uid = mm.uid_foreign')
->groupBy('mm.uid_local')
->execute()
->fetchAllAssociative()
;
return $this->indexTimestamps($rows, 'product');
}
/**
* Latest change to a hotel's matchcode aliases, by hotel uid. They are part of the hotel's
* `codes`, which the consumer joins its trip data on.
*
* @return array<int, int>
*/
public function findMatchcodeTimestamps(): array
{
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('tx_epproducts_domain_model_matchcode');
$queryBuilder->getRestrictions()->removeAll();
$rows = $queryBuilder
->selectLiteral('entity AS hotel', 'MAX(tstamp) AS tstamp')
->from('tx_epproducts_domain_model_matchcode')
->where($queryBuilder->expr()->eq('entity_type', $queryBuilder->createNamedParameter('hotel')))
->groupBy('entity')
->execute()
->fetchAllAssociative()
;
return $this->indexTimestamps($rows, 'hotel');
}
/**
* @return array<int, int>
*/
private function indexTimestamps(array $rows, string $key): array
{
$timestamps = [];
foreach ($rows as $row) {
$timestamps[(int) $row[$key]] = (int) $row['tstamp'];
}
return $timestamps;
}
private function addTypeConstraints(string $type, QueryBuilder $queryBuilder): void
{
$expr = $queryBuilder->expr();
if ('product' === $type) {
// A product that is neither searchable nor bookable is an internal record.
$queryBuilder->andWhere($expr->orX($expr->eq('searchable', 1), $expr->eq('bookable', 1)));
}
if ('news' === $type) {
// Type 0 is a regular article; 1 and 2 are just links to a page or an external URL.
$queryBuilder->andWhere(
$expr->eq('type', $queryBuilder->createNamedParameter('0')),
$expr->in('fe_group', $queryBuilder->createNamedParameter(['', '0'], Connection::PARAM_STR_ARRAY))
);
}
}
}
@@ -0,0 +1,513 @@
<?php
namespace EP\EpProducts\ContentFeed;
use EP\EpProducts\Utility\HotelIconUtility;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
/**
* Builds GET /api/content/records: the editorial content of products, hotels, destinations,
* concepts and blog articles. Filter attributes and text only - no dates, prices or images.
* Dates and prices are the consumer's own data; images play no part in a text chatbot.
*
* Rich-text fields go out as stored HTML with `t3://` links resolved; the consumer converts
* them to Markdown together with the rendered pages, so there is one HTML-to-text step.
*
* See .ddev/plans/CHATBOT-MCP-01-TYPO3-CONTENT-FEED.md §5.
*/
class RecordSerializer
{
/**
* @var RecordFinder
*/
private $recordFinder;
/**
* @var UrlResolver
*/
private $urlResolver;
/**
* @var RteLinkResolver
*/
private $rteLinkResolver;
/**
* @var ConnectionPool
*/
private $connectionPool;
public function __construct(
RecordFinder $recordFinder,
UrlResolver $urlResolver,
RteLinkResolver $rteLinkResolver,
ConnectionPool $connectionPool
) {
$this->recordFinder = $recordFinder;
$this->urlResolver = $urlResolver;
$this->rteLinkResolver = $rteLinkResolver;
$this->connectionPool = $connectionPool;
}
/**
* @param int[] $uids
* @return array[] one item per eligible uid; ineligible uids are left out
*/
public function serialize(string $type, array $uids): array
{
$rows = $this->recordFinder->find($type, ['*'], $uids);
if ([] === $rows) {
return [];
}
switch ($type) {
case 'product':
return $this->serializeProducts($rows);
case 'hotel':
return $this->serializeHotels($rows);
case 'news':
return $this->serializeNews($rows);
default:
return array_values(array_map(function (array $row) use ($type): array {
return $this->serializeDestination($type, $row);
}, $rows));
}
}
private function serializeProducts(array $rows): array
{
$uids = array_keys($rows);
$hotels = $this->findMmUids('tx_epproducts_product_hotel_mm', 'uid_local', 'uid_foreign', $uids);
$regions = $this->findMmUids('tx_epproducts_product_region_mm', 'uid_local', 'uid_foreign', $uids);
$faqs = $this->findFaqs($uids);
$faqTimestamps = $this->recordFinder->findFaqTimestamps();
$infoboxes = $this->findInfoboxTexts(array_column($rows, 'non_bookable_info'));
$items = [];
foreach ($rows as $uid => $row) {
$season = trim((string) $row['season']);
$items[] = $this->withLink($row, max((int) $row['tstamp'], $faqTimestamps[$uid] ?? 0)) + [
'code' => $this->text($row['code']),
'busProId' => (int) $row['bus_pro_id'] ?: null,
'name' => $this->text($row['name']),
'subline' => $this->text($row['subline']),
'headline' => $this->text($row['headline']),
'season' => '' === $season ? 'w' : $season,
'daytrip' => (bool) $row['daytrip'],
'bookable' => (bool) $row['bookable'],
'searchable' => (bool) $row['searchable'],
'skipassIncluded' => (bool) $row['skipass_included'],
'conceptUid' => (int) $row['concept'] ?: null,
'countryUid' => (int) $row['country'] ?: null,
'regionUid' => (int) $row['region'] ?: null,
'cityUid' => (int) $row['city'] ?: null,
'additionalRegionUids' => $regions[$uid] ?? [],
'hotelUids' => $hotels[$uid] ?? [],
'keywords' => $this->text($row['keywords']),
'text' => [
'teaser' => $this->html($row['teaser']),
'teaserLong' => $this->html($row['teaser_long']),
'feature' => $this->text($row['feature']),
'conceptDescription' => $this->html($row['concept_description']),
'boardDescription' => $this->html($row['board_description']),
'includedServices' => $this->html($row['included_services']),
'additionalServices' => $this->html($row['additional_services']),
'programmeDescription' => $this->html($row['programme_description']),
'skiPassDescription' => $this->html($row['ski_pass_description']),
'nonBookableInfo' => $infoboxes[(int) $row['non_bookable_info']] ?? null,
],
'faqs' => $faqs[$uid] ?? [],
];
}
return $items;
}
private function serializeHotels(array $rows): array
{
$uids = array_keys($rows);
$aliases = $this->findMatchcodes($uids);
$matchcodeTimestamps = $this->recordFinder->findMatchcodeTimestamps();
$products = $this->findMmUids('tx_epproducts_product_hotel_mm', 'uid_foreign', 'uid_local', $uids, 'sorting_foreign');
$eligibleProducts = $this->recordFinder->find('product', ['uid'], array_values(array_unique(array_merge([], ...array_values($products)))));
$items = [];
foreach ($rows as $uid => $row) {
$code = trim((string) $row['code']);
$codes = array_values(array_unique(array_filter(array_merge([$code], $aliases[$uid] ?? []), 'strlen')));
$items[] = $this->withLink($row, max((int) $row['tstamp'], $matchcodeTimestamps[$uid] ?? 0)) + [
'code' => '' === $code ? null : $code,
'codes' => $codes,
'name' => $this->text($row['name']),
'shortName' => $this->text($row['short_name']),
'headline' => $this->text($row['headline']),
'type' => (int) $row['type'],
'category' => (int) $row['category'],
'new' => (bool) $row['new'],
'earlybird' => (bool) $row['earlybird'],
'countryUid' => (int) $row['country'] ?: null,
'regionUid' => (int) $row['region'] ?: null,
'cityUid' => (int) $row['city'] ?: null,
'productUids' => array_values(array_filter($products[$uid] ?? [], function (int $productUid) use ($eligibleProducts): bool {
return isset($eligibleProducts[$productUid]);
})),
'address' => $this->text($row['address']),
'latitude' => $this->text($row['latitude']),
'longitude' => $this->text($row['longitude']),
'facts' => [
'bedsCount' => (int) $row['beds_count'] ?: null,
'parkingCount' => (int) $row['parking_count'] ?: null,
'altitude' => $this->text($row['altitude']),
'distanceBus' => $this->text($row['distance_bus']),
'distanceLift' => $this->text($row['distance_lift']),
'shower' => $this->text($row['shower']),
'partyroom' => (bool) $row['partyroom'],
'gamesroom' => (bool) $row['gamesroom'],
'sauna' => (bool) $row['sauna'],
'wifi' => (bool) $row['wifi'],
],
'icons' => HotelIconUtility::getIcons($row),
'keywords' => $this->text($row['keywords']),
'text' => [
'teaser' => $this->html($row['teaser']),
'description' => $this->html($row['description']),
'features' => $this->html($row['features']),
'roomTypes' => $this->html($row['room_types']),
'additionalInformation' => $this->html($row['additional_information']),
],
];
}
return $items;
}
private function serializeDestination(string $type, array $row): array
{
$item = $this->withLink($row, (int) $row['tstamp']) + [
'name' => $this->text($row['name']),
'headline' => $this->text($row['headline']),
];
switch ($type) {
case 'region':
return $item + [
'season' => $this->text($row['season']),
'keywords' => $this->text($row['keywords']),
'countryUid' => (int) $row['country'] ?: null,
'facts' => [
'length' => $this->text($row['length']),
'height' => $this->text($row['height']),
'lifts' => $this->text($row['lifts']),
],
'webcam' => $this->findWebcamUrl((int) $row['webcam']),
'text' => [
'teaser' => $this->html($row['teaser']),
'description' => $this->html($row['description']),
'feature' => $this->text($row['feature']),
'skiArea' => $this->html($row['ski_area']),
'skiAreaExtended' => $this->html($row['ski_area_extended']),
'skiPass' => $this->html($row['ski_pass']),
'news' => $this->html($row['news']),
],
];
case 'country':
return $item + [
'code' => $this->text($row['code']),
'season' => $this->text($row['season']),
'keywords' => $this->text($row['keywords']),
'text' => [
'teaser' => $this->html($row['teaser']),
'description' => $this->html($row['description']),
'descriptionExtended' => $this->html($row['description_extended']),
],
];
case 'city':
return $item + [
'season' => $this->text($row['season']),
'keywords' => $this->text($row['keywords']),
'countryUid' => (int) $row['country'] ?: null,
'regionUid' => (int) $row['region'] ?: null,
'text' => [
'teaser' => $this->html($row['teaser']),
'description' => $this->html($row['description']),
'descriptionExtended' => $this->html($row['description_extended']),
'party' => $this->html($row['party']),
'leisure' => $this->html($row['leisure']),
],
];
default: // concept
return $item + [
'code' => $this->text($row['code']),
'text' => [
'teaser' => $this->html($row['teaser']),
'description' => $this->html($row['description']),
'descriptionExtended' => $this->html($row['description_extended']),
'popupText' => $this->html($row['popup_text']),
],
];
}
}
private function serializeNews(array $rows): array
{
$uids = array_keys($rows);
$tags = $this->findNewsTags($uids);
$categories = $this->findNewsCategories($uids);
$items = [];
foreach ($rows as $uid => $row) {
$link = $this->urlResolver->getNewsLink($uid, (int) $row['pid']);
if (null === $link) {
continue;
}
$items[] = [
'uid' => $uid,
'url' => $link['url'],
'site' => $link['site'],
'modified' => date('c', (int) $row['tstamp']),
'title' => $this->text($row['title']),
'teaser' => $this->html($row['teaser']),
'bodytext' => $this->html($row['bodytext']),
'datetime' => (int) $row['datetime'] > 0 ? date('c', (int) $row['datetime']) : null,
'tags' => $tags[$uid] ?? [],
'categories' => $categories[$uid] ?? [],
];
}
return $items;
}
/**
* The identity and link fields every record carries, with the same values as the manifest.
*/
private function withLink(array $row, int $modified): array
{
$link = $this->urlResolver->getRecordLink((string) $row['detail_page']);
return [
'uid' => (int) $row['uid'],
'url' => $link['url'],
'site' => $link['site'],
'modified' => date('c', $modified),
];
}
/**
* @param int[] $uids
* @return array<int, int[]> related uids by $keyField, in $sortField order
*/
private function findMmUids(string $table, string $keyField, string $valueField, array $uids, string $sortField = 'sorting'): array
{
$queryBuilder = $this->connectionPool->getQueryBuilderForTable($table);
$rows = $queryBuilder
->select($keyField, $valueField)
->from($table)
->where($queryBuilder->expr()->in($keyField, $queryBuilder->createNamedParameter($uids, Connection::PARAM_INT_ARRAY)))
->orderBy($keyField)
->addOrderBy($sortField)
->execute()
->fetchAllAssociative()
;
$related = [];
foreach ($rows as $row) {
$related[(int) $row[$keyField]][] = (int) $row[$valueField];
}
return $related;
}
/**
* @param int[] $productUids
* @return array<int, array[]> FAQs by product uid, in the order the editor arranged them
*/
private function findFaqs(array $productUids): array
{
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('tx_epproducts_domain_model_faq');
$rows = $queryBuilder
->select('mm.uid_local AS product', 'faq.question', 'faq.answer', 'faq.category')
->from('tx_epproducts_domain_model_faq', 'faq')
->join('faq', 'tx_epproducts_product_faq_mm', 'mm', 'mm.uid_foreign = faq.uid')
->where($queryBuilder->expr()->in('mm.uid_local', $queryBuilder->createNamedParameter($productUids, Connection::PARAM_INT_ARRAY)))
->orderBy('mm.uid_local')
->addOrderBy('mm.sorting')
->execute()
->fetchAllAssociative()
;
$faqs = [];
foreach ($rows as $row) {
$faqs[(int) $row['product']][] = [
'question' => $this->text($row['question']),
'answer' => $this->html($row['answer']),
'category' => $this->text($row['category']),
];
}
return $faqs;
}
/**
* Matchcode aliases by hotel uid. With the hotel's own code they are every code BusPro may use
* for it - the same set DateImportService::getHotelMappings() resolves.
*
* @param int[] $hotelUids
* @return array<int, string[]>
*/
private function findMatchcodes(array $hotelUids): array
{
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('tx_epproducts_domain_model_matchcode');
$rows = $queryBuilder
->select('entity', 'code')
->from('tx_epproducts_domain_model_matchcode')
->where(
$queryBuilder->expr()->eq('entity_type', $queryBuilder->createNamedParameter('hotel')),
$queryBuilder->expr()->in('entity', $queryBuilder->createNamedParameter($hotelUids, Connection::PARAM_INT_ARRAY))
)
->orderBy('code')
->execute()
->fetchAllAssociative()
;
$codes = [];
foreach ($rows as $row) {
$codes[(int) $row['entity']][] = trim((string) $row['code']);
}
return $codes;
}
/**
* @param array $infoboxUids
* @return array<int, string|null>
*/
private function findInfoboxTexts(array $infoboxUids): array
{
$infoboxUids = array_values(array_filter(array_map('intval', $infoboxUids)));
if ([] === $infoboxUids) {
return [];
}
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('tx_epproducts_domain_model_infobox');
$rows = $queryBuilder
->select('uid', 'text')
->from('tx_epproducts_domain_model_infobox')
->where($queryBuilder->expr()->in('uid', $queryBuilder->createNamedParameter(array_unique($infoboxUids), Connection::PARAM_INT_ARRAY)))
->execute()
->fetchAllAssociative()
;
$texts = [];
foreach ($rows as $row) {
$texts[(int) $row['uid']] = $this->html($row['text']);
}
return $texts;
}
private function findWebcamUrl(int $webcamUid): ?string
{
if (0 === $webcamUid) {
return null;
}
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('tx_epproducts_domain_model_webcam');
$url = $queryBuilder
->select('url')
->from('tx_epproducts_domain_model_webcam')
->where($queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($webcamUid, \PDO::PARAM_INT)))
->execute()
->fetchOne()
;
return false === $url ? null : $this->text($url);
}
/**
* @param int[] $newsUids
* @return array<int, string[]>
*/
private function findNewsTags(array $newsUids): array
{
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('tx_news_domain_model_tag');
$rows = $queryBuilder
->select('mm.uid_local AS news', 'tag.title')
->from('tx_news_domain_model_tag', 'tag')
->join('tag', 'tx_news_domain_model_news_tag_mm', 'mm', 'mm.uid_foreign = tag.uid')
->where($queryBuilder->expr()->in('mm.uid_local', $queryBuilder->createNamedParameter($newsUids, Connection::PARAM_INT_ARRAY)))
->orderBy('mm.sorting')
->execute()
->fetchAllAssociative()
;
$tags = [];
foreach ($rows as $row) {
$tags[(int) $row['news']][] = trim((string) $row['title']);
}
return $tags;
}
/**
* @param int[] $newsUids
* @return array<int, string[]>
*/
private function findNewsCategories(array $newsUids): array
{
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('sys_category');
$rows = $queryBuilder
->select('mm.uid_foreign AS news', 'category.title')
->from('sys_category', 'category')
->join('category', 'sys_category_record_mm', 'mm', 'mm.uid_local = category.uid')
->where(
$queryBuilder->expr()->eq('mm.tablenames', $queryBuilder->createNamedParameter('tx_news_domain_model_news')),
$queryBuilder->expr()->eq('mm.fieldname', $queryBuilder->createNamedParameter('categories')),
$queryBuilder->expr()->in('mm.uid_foreign', $queryBuilder->createNamedParameter($newsUids, Connection::PARAM_INT_ARRAY))
)
->orderBy('mm.sorting_foreign')
->execute()
->fetchAllAssociative()
;
$categories = [];
foreach ($rows as $row) {
$categories[(int) $row['news']][] = trim((string) $row['title']);
}
return $categories;
}
/**
* Rich text as stored, with internal links made absolute.
*/
private function html($value): ?string
{
$value = trim((string) $value);
return '' === $value ? null : $this->rteLinkResolver->resolve($value);
}
/**
* Plain text with whitespace collapsed. Product names carry literal line breaks the website
* splits on for layout ("Apartments \nVal Thorens"); the chatbot needs them as one line.
*/
private function text($value): ?string
{
$value = trim((string) preg_replace('/\s+/u', ' ', (string) $value));
return '' === $value ? null : $value;
}
}
@@ -0,0 +1,104 @@
<?php
namespace EP\EpProducts\ContentFeed;
use TYPO3\CMS\Core\LinkHandling\LinkService;
use TYPO3\CMS\Core\Resource\File;
/**
* Rewrites `t3://` links in stored RTE HTML to absolute URLs.
*
* parseFunc_RTE would do this, but it needs a TSFE and the API middleware runs before one exists.
* Only links are touched; the rest of the HTML is passed on as stored. A link that cannot be
* resolved to something public (a page outside the feed's sites, a deleted page) loses its href
* and keeps its text.
*/
class RteLinkResolver
{
/**
* @var LinkService
*/
private $linkService;
/**
* @var UrlResolver
*/
private $urlResolver;
public function __construct(LinkService $linkService, UrlResolver $urlResolver)
{
$this->linkService = $linkService;
$this->urlResolver = $urlResolver;
}
public function resolve(string $html): string
{
if (false === strpos($html, 't3://')) {
return $html;
}
return (string) preg_replace_callback(
'/\shref=(["\'])(t3:\/\/[^"\']*)\1/i',
function (array $matches): string {
$url = $this->resolveLink(html_entity_decode($matches[2], ENT_QUOTES | ENT_HTML5));
return null === $url ? '' : ' href="' . htmlspecialchars($url) . '"';
},
$html
);
}
private function resolveLink(string $link): ?string
{
try {
$data = $this->linkService->resolve($link);
} catch (\Throwable $e) {
return null;
}
if (LinkService::TYPE_PAGE === ($data['type'] ?? null)) {
$pageUid = $this->urlResolver->parsePageReference('t3://page?uid=' . ($data['pageuid'] ?? ''));
$target = null === $pageUid ? null : $this->urlResolver->resolveLinkTarget($pageUid);
$url = null === $target ? null : $this->urlResolver->getPageUrl($target);
if (null !== $url && '' !== (string) ($data['fragment'] ?? '')) {
$url .= '#' . $data['fragment'];
}
return $url;
}
if (LinkService::TYPE_FILE === ($data['type'] ?? null) && ($data['file'] ?? null) instanceof File) {
return $this->absolute((string) $data['file']->getPublicUrl());
}
if (LinkService::TYPE_URL === ($data['type'] ?? null)) {
return (string) $data['url'];
}
return null;
}
/**
* File URLs come back relative to the document root; the consumer has no page to resolve
* them against for record text, so make them absolute against the main site.
*/
private function absolute(string $url): ?string
{
if ('' === $url) {
return null;
}
if (1 === preg_match('/^https?:\/\//', $url)) {
return $url;
}
$sites = $this->urlResolver->getIncludedSites();
if ([] === $sites) {
return null;
}
return rtrim((string) $sites[0]->getBase(), '/') . '/' . ltrim($url, '/');
}
}
@@ -0,0 +1,214 @@
<?php
namespace EP\EpProducts\ContentFeed;
use TYPO3\CMS\Core\Exception\SiteNotFoundException;
use TYPO3\CMS\Core\Site\Entity\Site;
use TYPO3\CMS\Core\Site\SiteFinder;
use TYPO3\CMS\Core\Utility\MathUtility;
/**
* Absolute public URLs for the content feed, generated through each site's router so that
* baseVariants apply (staging and DDEV get their own hosts) and route enhancers shape the path.
*/
class UrlResolver
{
private const DOKTYPE_DEFAULT = 1;
private const DOKTYPE_SHORTCUT = 4;
private const SHORTCUT_MODE_NONE = 0;
private const SHORTCUT_MODE_FIRST_SUBPAGE = 1;
private const SHORTCUT_MODE_PARENT_PAGE = 3;
private const MAX_SHORTCUT_DEPTH = 5;
/**
* @var SiteFinder
*/
private $siteFinder;
/**
* @var PageTree
*/
private $pageTree;
/**
* @var string[]
*/
private $includedSites;
/**
* @var array<string, int> news detail page uid by site identifier
*/
private $newsDetailPages;
/**
* @var array<int, Site|null>
*/
private $sitesByPage = [];
public function __construct(SiteFinder $siteFinder, PageTree $pageTree, ContentFeedConfiguration $configuration)
{
$this->siteFinder = $siteFinder;
$this->pageTree = $pageTree;
$this->includedSites = $configuration->getSites();
$this->newsDetailPages = $configuration->getNewsDetailPages();
}
/**
* @return Site[] included sites, in configuration order
*/
public function getIncludedSites(): array
{
$sites = [];
foreach ($this->includedSites as $identifier) {
try {
$sites[] = $this->siteFinder->getSiteByIdentifier($identifier);
} catch (SiteNotFoundException $e) {
// A misspelt identifier must not take the whole feed down; it just contributes nothing.
}
}
return $sites;
}
/**
* The page's site, or null when it belongs to no site or to one outside the feed.
*/
public function getIncludedSite(int $pageUid): ?Site
{
if (!array_key_exists($pageUid, $this->sitesByPage)) {
try {
$site = $this->siteFinder->getSiteByPageId($pageUid);
$this->sitesByPage[$pageUid] = in_array($site->getIdentifier(), $this->includedSites, true) ? $site : null;
} catch (SiteNotFoundException $e) {
$this->sitesByPage[$pageUid] = null;
}
}
return $this->sitesByPage[$pageUid];
}
public function getPageUrl(int $pageUid, int $languageId = 0, array $parameters = []): ?string
{
$site = $this->getIncludedSite($pageUid);
if (null === $site) {
return null;
}
try {
$language = $site->getLanguageById($languageId);
return (string) $site->getRouter()->generateUri($pageUid, ['_language' => $language] + $parameters);
} catch (\Throwable $e) {
// Unroutable pages (missing slug, disabled language) are left out rather than failing the feed.
return null;
}
}
/**
* Parses a typolink page reference as stored in `detail_page`: a plain uid or `t3://page?uid=N`.
*/
public function parsePageReference(string $reference): ?int
{
$reference = trim($reference);
if (MathUtility::canBeInterpretedAsInteger($reference)) {
return (int) $reference > 0 ? (int) $reference : null;
}
if (1 === preg_match('/^t3:\/\/page\?(?:.*&)?uid=(\d+)/', html_entity_decode($reference), $matches)) {
return (int) $matches[1];
}
return null;
}
/**
* Follows shortcut pages the way a typolink does, and returns the uid of the visible standard
* page a link to $pageUid ends up on - or null when the chain breaks or loops.
*/
public function resolveLinkTarget(int $pageUid): ?int
{
for ($depth = 0; $depth < self::MAX_SHORTCUT_DEPTH; $depth++) {
$page = $this->pageTree->getPage($pageUid);
if (null === $page || !$this->pageTree->isVisible($page)) {
return null;
}
if ((int) $page['doktype'] !== self::DOKTYPE_SHORTCUT) {
return (int) $page['doktype'] === self::DOKTYPE_DEFAULT ? $pageUid : null;
}
$next = $this->getShortcutTarget($page);
if (null === $next) {
return null;
}
$pageUid = $next;
}
return null;
}
/**
* @return array{url: ?string, site: ?string}
*/
public function getRecordLink(string $detailPage): array
{
$pageUid = $this->parsePageReference($detailPage);
$target = null === $pageUid ? null : $this->resolveLinkTarget($pageUid);
$site = null === $target ? null : $this->getIncludedSite($target);
$url = null === $site ? null : $this->getPageUrl($target);
return [
'url' => $url,
'site' => null === $url ? null : $site->getIdentifier(),
];
}
/**
* News has no detail_page of its own: the storage folder decides the site, and the site's
* configured detail page carries the article through the NewsDetailPlugin route enhancer.
*
* @return array{url: ?string, site: string}|null null when the article is stored outside the feed's sites
*/
public function getNewsLink(int $newsUid, int $storagePid): ?array
{
$site = $this->getIncludedSite($storagePid);
if (null === $site) {
return null;
}
$detailPage = $this->newsDetailPages[$site->getIdentifier()] ?? null;
$url = null === $detailPage ? null : $this->getPageUrl($detailPage, 0, [
'tx_news_pi1' => ['action' => 'detail', 'controller' => 'News', 'news' => $newsUid],
]);
return ['url' => $url, 'site' => $site->getIdentifier()];
}
private function getShortcutTarget(array $page): ?int
{
switch ((int) $page['shortcut_mode']) {
case self::SHORTCUT_MODE_NONE:
return (int) $page['shortcut'] > 0 ? (int) $page['shortcut'] : null;
case self::SHORTCUT_MODE_FIRST_SUBPAGE:
foreach ($this->pageTree->getChildren((int) $page['uid']) as $childUid) {
if ($this->pageTree->isVisible($this->pageTree->getPage($childUid))) {
return $childUid;
}
}
return null;
case self::SHORTCUT_MODE_PARENT_PAGE:
return (int) $page['pid'] > 0 ? (int) $page['pid'] : null;
default:
// Random subpage: there is no stable URL to give.
return null;
}
}
}
@@ -0,0 +1,391 @@
<?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,
]));
}
}
@@ -0,0 +1,102 @@
<?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);
}
}
@@ -0,0 +1,148 @@
<?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);
}
}
@@ -0,0 +1,100 @@
<?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',
]);
}
}
@@ -0,0 +1,132 @@
<?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,
],
]);
}
}
@@ -0,0 +1,386 @@
<?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\Date;
use EP\EpProducts\Domain\Model\Hotel;
use EP\EpProducts\Domain\Model\Product;
use EP\EpProducts\Domain\Repository\InfoboxRepository;
use EP\EpProducts\Domain\Repository\ProductRepository;
use EP\EpProducts\Service\ContingentDataService;
use EP\EpProducts\Service\DateService;
use EP\EpProducts\Service\FilterService;
use EP\EpProducts\Service\MyEpUrlResolverService;
use EP\EpProducts\Service\ResellerDataService;
use EP\EpProducts\Traits\RequestArgumentTypeConversionTrait;
use League\Period\Period;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
class AjaxTableController extends ActionController
{
use RequestArgumentTypeConversionTrait;
/**
* @var ProductRepository
*/
protected $productRepository;
/**
* @var InfoboxRepository
*/
protected $infoboxRepository;
/**
* @var \EP\EpProducts\Service\FilterService
*/
protected $filterService;
/**
* @var DateService
*/
protected $dateService;
/**
* @var ResellerDataService
*/
protected $resellerDataService;
/**
* @var ContingentDataService
*/
protected $contingentDataService;
/**
* @var MyEpUrlResolverService
*/
protected $myEpUrlResolverService;
/**
* @param ProductRepository $productRepository
* @param InfoboxRepository $infoboxRepository
* @param DateService $dateService
* @param FilterService $filterService
* @param ResellerDataService $resellerDataService
* @param ContingentDataService $contingentDataService
* @param MyEpUrlResolverService $myEpUrlResolverService
*/
public function __construct(
ProductRepository $productRepository,
InfoboxRepository $infoboxRepository,
DateService $dateService,
FilterService $filterService,
ResellerDataService $resellerDataService,
ContingentDataService $contingentDataService,
MyEpUrlResolverService $myEpUrlResolverService
) {
$this->productRepository = $productRepository;
$this->infoboxRepository = $infoboxRepository;
$this->dateService = $dateService;
$this->filterService = $filterService;
$this->resellerDataService = $resellerDataService;
$this->contingentDataService = $contingentDataService;
$this->myEpUrlResolverService = $myEpUrlResolverService;
}
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|null $dateFrom
* @param string|null $dateTo
*/
public function datestableAction(
Product $product,
Hotel $hotel,
string $dateFrom = null,
string $dateTo = null
): void {
$forcedConceptUids = GeneralUtility::trimExplode(',', $this->settings['forcedConceptUids'], true);
$filterSettings = $this->filterService->getNormalizedFilterSettings([], $forcedConceptUids);
$filterSettings['dateFrom'] = $dateFrom;
$filterSettings['dateTo'] = $dateTo;
$paCode = GeneralUtility::_GET('pa');
$myEpUrl = $this->myEpUrlResolverService->resolve();
$dates = $this->dateService->getDatesTable([
'product' => $product,
'hotel' => $hotel,
'filterSettings' => $filterSettings,
]);
if (1 === count($dates)) {
$date = reset($dates);
$this->forward(
'pricetable',
null,
'ep_products',
[
'product' => $product,
'hotel' => $hotel,
'date' => $date['dateUid'],
'paCode' => $paCode,
'singleDate' => true,
]
);
}
$nonBookableDateUids = GeneralUtility::trimExplode(',', $product->getNonBookableDates(), true);
$allDates = $this->dateService->preprocessDatesTable([
'dateTableData' => $dates,
'myEpUrl' => $myEpUrl,
'paCode' => $paCode,
'showBookingButton' => false === $product->getHideBookingButton(),
'nonBookableDateUids' => $nonBookableDateUids,
]);
$bookableDates = array_filter($allDates, function (array $date) {
return $date['available'] > 0;
});
$includedServices = $this->dateService->groupIncludedServices($bookableDates);
$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();
}
}
$hasSurchargeOrDiscount = $this->dateService->checkSurcharcheOrDiscount($allDates);
// $hasIncludedServices = $this->dateService->hasIncludedServices($allDates);
$hasIncludedServices = true;
$noInfoConceptUids = GeneralUtility::trimExplode(',', $this->settings['noInfoConceptUids']);
$isProductWithNoInfoConcept = ($product->getConcept() !== null) && \in_array($product->getConcept()->getUid(),
$noInfoConceptUids, false);
$nonBookableInfo = $this->getNonBookableInfobox($product);
$this->view->assignMultiple([
'allDates' => $allDates,
'bookableDates' => $bookableDates,
'includedServicesAllDates' => $includedServices['allDates'],
'includedServicesSomeDates' => $includedServices['someDates'],
'bookable' => $product->getBookable(),
'unavailable' => 0 === count($allDates),
'product' => $product,
'hotel' => $hotel,
'altProductLink' => $altProductLink,
'altLabel' => $altLabel,
'hasIncludedServices' => $hasIncludedServices,
'hasSurcharge' => $hasSurchargeOrDiscount['surcharge'],
'hasDiscount' => $hasSurchargeOrDiscount['discount'],
'isProductWithNoInfoConcept' => $isProductWithNoInfoConcept,
'nonBookableInfo' => $nonBookableInfo,
'myEpUrl' => $myEpUrl,
]);
}
/**
* @param Product $product
* @param Hotel $hotel
* @param Date $date
* @param bool $singleDate
*/
public function pricetableAction(
Product $product,
Hotel $hotel,
Date $date,
bool $singleDate = false
): void {
$forcedConceptUids = GeneralUtility::trimExplode(',', $this->settings['forcedConceptUids'], true);
$filterSettings = $this->filterService->getNormalizedFilterSettings([], $forcedConceptUids);
$myEpUrl = $this->myEpUrlResolverService->resolve();
$priceTable = $this->dateService->getPriceTable([
'product' => $product,
'hotel' => $hotel,
'filterSettings' => $filterSettings,
'date' => $date,
'myEpUrl' => $myEpUrl,
'paCode' => GeneralUtility::_GET('pa'),
]);
$hasSurchargeOrDiscount = $this->dateService->checkSurcharcheOrDiscount($priceTable);
$hasIncludedServices = $this->dateService->hasIncludedServices($priceTable);
$dateStart = $date ? $date->getDateStart()->format('d.m.y') : '';
$dateEnd = $date ? $date->getDateEnd()->format('d.m.y') : '';
$dateRange = sprintf('%s - %s', $dateStart, $dateEnd);
$noInfoConceptUids = GeneralUtility::trimExplode(',', $this->settings['noInfoConceptUids']);
$isProductWithNoInfoConcept = ($product->getConcept() !== null) && \in_array($product->getConcept()->getUid(), $noInfoConceptUids);
$nonBookableInfo = $this->getNonBookableInfobox($product);
$this->view->assignMultiple([
'dateRange' => $dateRange,
'product' => $product,
'hotel' => $hotel,
'servicesIncluded' => $date->getServicesIncluded(),
'prices' => $priceTable,
'unavailable' => 0 === count($priceTable),
'hasIncludedServices' => $hasIncludedServices,
'hasSurcharge' => $hasSurchargeOrDiscount['surcharge'],
'hasDiscount' => $hasSurchargeOrDiscount['discount'],
'isProductWithNoInfoConcept' => $isProductWithNoInfoConcept,
'isSingleDate' => $singleDate,
'nonBookableInfo' => $nonBookableInfo,
'myEpUrl' => $myEpUrl,
]);
}
/**
* @param Product $product
* @param Hotel $hotel
*/
public function pricetableHtmlAction(Product $product, Hotel $hotel): void
{
$nonBookableInfo = $this->getNonBookableInfobox($product);
$myEpUrl = $this->myEpUrlResolverService->resolve();
$priceTable = $this->dateService->getPriceTable([
'product' => $product,
'hotel' => $hotel,
'filterSettings' => $this->filterService->getNormalizedFilterSettings(),
'myEpUrl' => $myEpUrl,
'paCode' => GeneralUtility::_GET('pa'),
'sortByRoom' => true,
]);
$hasIncludedServices = $this->dateService->hasIncludedServices($priceTable);
$this->view->assignMultiple([
'pricetable' => $priceTable,
'hasIncludedServices' => $hasIncludedServices,
'nonBookableInfo' => $nonBookableInfo,
'myEpUrl' => $myEpUrl,
]);
}
/**
* @param Product $product
*/
public function eventPricetableAction(Product $product): void
{
$roomTypes = GeneralUtility::trimExplode(',', $this->settings['priceTableRoomTypes']);
$roomTypesPax = array_map(function ($type) {
return (int) $type;
}, $roomTypes);
$roomTypesLabels = array_map(function ($type) {
$label = (int) $type . 'er';
if (false !== strpos($type, '+')) {
$label .= '+';
}
return $label;
}, $roomTypes);
$maxPax = max($roomTypesPax);
$myEpUrl = $this->myEpUrlResolverService->resolve();
$priceTable = $this->dateService->getEventPriceTable($product, $maxPax, $myEpUrl);
$hasIncludedServices = $this->dateService->hasIncludedServices($priceTable);
$nonBookableInfo = $this->getNonBookableInfobox($product);
$categories = [
Hotel::CATEGORY_STANDARD => 'Standard',
Hotel::CATEGORY_COMFORT => 'Komfort',
Hotel::CATEGORY_DELUXE => 'Deluxe',
Hotel::CATEGORY_SUPER_DELUXE => 'Super Deluxe',
];
$this->view->assignMultiple([
'roomTypesPax' => $roomTypesPax,
'roomTypesLabels' => $roomTypesLabels,
'pricetable' => $priceTable,
'hasIncludedServices' => $hasIncludedServices,
'categories' => $categories,
'themekey' => $this->settings['themekey'],
'nonBookableInfo' => $nonBookableInfo,
'myEpUrl' => $myEpUrl,
]);
}
/**
* @param Hotel $hotel
* @param Product $product
* @param string $dateFrom
* @param string $dateTo
*/
public function daytripRoomsAction(
Hotel $hotel,
Product $product,
string $dateFrom,
string $dateTo
): void {
$period = new Period($dateFrom, $dateTo);
$nights = (int) $period->dateInterval()->format('%a') + 1;
$myEpUrl = $this->myEpUrlResolverService->resolve();
if (2 > $nights) {
$rooms = [];
} else {
$rooms = $this
->contingentDataService
->getAvailableRooms($dateFrom, $dateTo, $hotel, $product, $myEpUrl);
}
$this->view->assign('nights', $nights);
$this->view->assign('rooms', $rooms);
$this->view->assign('myEpUrl', $myEpUrl);
}
/**
* @param Product $product
* @return \EP\EpProducts\Domain\Model\Infobox
*/
protected function getNonBookableInfobox(Product $product)
{
if (null !== $nonBookableInfo = $product->getNonBookableInfo()) {
return $nonBookableInfo;
}
return $this->infoboxRepository->getDefault();
}
}
@@ -0,0 +1,17 @@
<?php
namespace EP\EpProducts\Controller;
use EP\EpProducts\Domain\Model\Concept;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
class AjaxTeaserPopupController extends ActionController
{
public function conceptAction(Concept $concept, string $targetUrl)
{
$this->view->assignMultiple([
'concept' => $concept,
'targetUrl' => $targetUrl,
]);
}
}
@@ -0,0 +1,104 @@
<?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()
]);
}
}
@@ -0,0 +1,149 @@
<?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;
}
}
@@ -0,0 +1,97 @@
<?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);
}
}
@@ -0,0 +1,104 @@
<?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);
}
}
@@ -0,0 +1,79 @@
<?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);
}
}
@@ -0,0 +1,56 @@
<?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);
}
}
@@ -0,0 +1,152 @@
<?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);
}
}
@@ -0,0 +1,56 @@
<?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);
}
}
@@ -0,0 +1,123 @@
<?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,
]
);
}
}
@@ -0,0 +1,80 @@
<?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);
}
}
@@ -0,0 +1,41 @@
<?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);
}
}
@@ -0,0 +1,261 @@
<?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\HotelRepository;
use EP\EpProducts\Domain\Repository\InfoboxRepository;
use EP\EpProducts\Domain\Repository\ProductRepository;
use EP\EpProducts\Service\ContingentDataService;
use EP\EpProducts\Service\DateService;
use EP\EpProducts\Service\FilterService;
use EP\EpProducts\Service\HotelDataService;
use EP\EpProducts\Service\PickupOverviewService;
use EP\EpProducts\Service\ProductDataService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
class ProductController extends ActionController
{
/**
* @var \EP\EpProducts\Domain\Repository\ProductRepository
*/
protected $productRepository;
/**
* @var \EP\EpProducts\Domain\Repository\HotelRepository
*/
protected $hotelRepository;
/**
* @var \EP\EpProducts\Service\FilterService
*/
protected $filterService;
/**
* @var \EP\EpProducts\Service\ProductDataService
*/
protected $productDataService;
/**
* @var DateService
*/
protected $dateService;
/**
* @var HotelDataService
*/
protected $hotelDataService;
/**
* @var ContingentDataService
*/
private $contingentDataService;
/**
* @var InfoboxRepository
*/
private $infoboxRepository;
/**
* @var PickupOverviewService
*/
private $pickupOverviewService;
/**
* @param ProductRepository $productRepository
* @param ProductDataService $productDataService
* @param HotelRepository $hotelRepository
* @param HotelDataService $hotelDataService
* @param ContingentDataService $contingentDataService
* @param DateService $dateService
* @param FilterService $filterService
* @param InfoboxRepository $infoboxRepository
* @param PickupOverviewService $pickupOverviewService
*/
public function __construct(
ProductRepository $productRepository,
ProductDataService $productDataService,
HotelRepository $hotelRepository,
HotelDataService $hotelDataService,
ContingentDataService $contingentDataService,
DateService $dateService,
FilterService $filterService,
InfoboxRepository $infoboxRepository,
PickupOverviewService $pickupOverviewService
) {
$this->productRepository = $productRepository;
$this->productDataService = $productDataService;
$this->hotelRepository = $hotelRepository;
$this->hotelDataService = $hotelDataService;
$this->contingentDataService = $contingentDataService;
$this->dateService = $dateService;
$this->filterService = $filterService;
$this->infoboxRepository = $infoboxRepository;
$this->pickupOverviewService = $pickupOverviewService;
}
/**
* @param Product $product
* @param Hotel $hotel
* @param string $dateFrom
* @param string $dateTo
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException
*/
public function detailAction(
Product $product = null,
Hotel $hotel = null,
$dateFrom = null,
$dateTo = null
): void {
// Get product to display from flexform settings if not provided via url
if ($product === null) {
$productUid = $this->settings['productUid'];
$product = $this->productRepository->findByIdentifier($productUid);
}
// Redirect to search page in case no product can be determined
if ($product === null) {
$filterSettings = $this->filterService->getNormalizedFilterSettings();
$this->redirect(
'searchresult',
'Search',
null,
['filterSettings' => $filterSettings],
$this->settings['defaultSearchPageUid']
);
}
// Get hotel to display from flexform settings if not provided via url
if ((int)$this->settings['hotelUid'] > 0) {
$hotelUid = $this->settings['hotelUid'];
$hotel = $this->hotelRepository->findByIdentifier($hotelUid);
}
if ($hotel === null) {
// Forward to hotel list action in case multiple hotels are assigned to this product
if ($product->getHotels()->count() > 1) {
$arguments = [
'product' => $product,
];
$this->forward('hotelList', null, null, $arguments);
}
// Use first hotel which should be the only one at this point
if ($product->getHotels()->count() > 0) {
$product->getHotels()->rewind();
$hotel = $product->getHotels()->current();
}
}
if ($product->isDaytrip()) {
$availableContingents = $this
->contingentDataService
->getAvailableContingents($hotel, $product)
;
$enabledDates = array_keys($availableContingents);
}
$concept = $product->getConcept();
$excludedConceptUids = GeneralUtility::trimExplode(',', $this->settings['excludedConceptUids'], true);
$isProductWithExcludedConcept = ($concept !== null) && \in_array($concept->getUid(), $excludedConceptUids);
$noInfoConceptUids = GeneralUtility::trimExplode(',', $this->settings['noInfoConceptUids'], true);
$isProductWithNoInfoConcept = ($concept !== null) && \in_array($concept->getUid(), $noInfoConceptUids);
$groupInquiryFormConceptUids = GeneralUtility::trimExplode(',', $this->settings['groupInquiryFormConceptUids'], true);
$isProductWithGroupInquiryForm = ($concept !== null) && \in_array($concept->getUid(), $groupInquiryFormConceptUids);
$nonBookableInfo = $product->getNonBookableInfo();
// Assemble backlink
$backlinkUrl = GeneralUtility::_GET('ref');
$backLinkLabel = strpos($backlinkUrl, 'suche') !== -1 ? 'zurück zum Suchergebnis' : 'zurück';
$this->view->assignMultiple([
'hotel' => $hotel,
'product' => $product,
'enabledDates' => $enabledDates ?? [],
'isProductWithExcludedConcept' => $isProductWithExcludedConcept,
'isProductWithNoInfoConcept' => $isProductWithNoInfoConcept,
'isProductWithGroupInquiryForm' => $isProductWithGroupInquiryForm,
'currentPageUid' => $GLOBALS['TSFE']->id,
'dateFrom' => $dateFrom,
'dateTo' => $dateTo,
'referringUrl' => $backlinkUrl,
'backlinkLabel' => $backLinkLabel,
'nonBookableInfo' => $nonBookableInfo,
'pickupsOverview' => $this->pickupOverviewService->getOverview($product, $hotel),
]);
}
public function pricetableAction(): void
{
$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);
$pricetable = $this->dateService->getPriceTable([
'product' => $product,
'hotel' => $hotel,
'filterSettings' => $this->filterService->getNormalizedFilterSettings(),
]);
$this->view->assign('pricetable', $pricetable);
}
/**
* @param Product $product
*/
public function hotelListAction(Product $product): void
{
$hotels = $this->hotelDataService->getList($product);
$this->view->assignMultiple([
'hotels' => $hotels,
'product' => $product,
'linkHotel' => true,
]);
}
public function teasergroupAction(): void
{
$filterSettings = $this->filterService->getFiltersettingsFromSettings($this->settings);
$dateAuto = !$this->settings['dateFrom'] && !$this->settings['dateTo'];
$excludedConceptUids = GeneralUtility::trimExplode(',', $this->settings['excludedConceptUids'], true);
$limit = $this->settings['hideMoreLink'] ? 0 : 6;
$teasers = $this->productDataService->getTeasergroup($filterSettings, $excludedConceptUids, $limit);
$dateFrom = $this->settings['dateFrom'] ? date('Y-m-d', $this->settings['dateFrom']) : null;
$dateTo = $this->settings['dateTo'] ? date('Y-m-d', $this->settings['dateTo']) : null;
$data = $this->configurationManager->getContentObject()->data;
$nonBookableInfo = $this->settings['infoboxUid'] ? $this->infoboxRepository->findByUid($this->settings['infoboxUid']) : $this->infoboxRepository->getDefault();
$this->view->assign('data', $data);
$this->view->assign('teasers', $teasers);
$this->view->assign('dateAuto', $dateAuto);
$this->view->assign('filterSettings', $filterSettings);
$this->view->assign('dateFrom', $dateFrom);
$this->view->assign('dateTo', $dateTo);
$this->view->assign('nonBookableInfo', $nonBookableInfo);
}
}
@@ -0,0 +1,95 @@
<?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);
}
}
@@ -0,0 +1,99 @@
<?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);
}
}
@@ -0,0 +1,168 @@
<?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,
],
]);
}
}
@@ -0,0 +1,87 @@
<?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'],
]);
}
}
@@ -0,0 +1,59 @@
<?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);
}
}
@@ -0,0 +1,96 @@
<?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 '';
}
}
@@ -0,0 +1,105 @@
<?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);
}
}
@@ -0,0 +1,42 @@
<?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);
}
}
@@ -0,0 +1,66 @@
<?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;
}
}
@@ -0,0 +1,58 @@
<?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;
}
}
@@ -0,0 +1,420 @@
<?php
namespace EP\EpProducts\Domain\Model;
/***************************************************************
*
* Copyright notice
*
* (c) 2016 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
class AbstractDestination extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{
const SEASON_WINTER = 'w';
const SEASON_SUMMER = 's';
/**
* @var string
*/
protected $detailPage;
/**
* @var string
*/
protected $season = self::SEASON_WINTER;
/**
* @var float
*/
protected $latitude = 0.0;
/**
* @var float
*/
protected $longitude = 0.0;
/**
* @var string
*/
protected $name = '';
/**
* @var string
*/
protected $nameInternal = '';
/**
* @var string
*/
protected $keywords = '';
/**
* @var string
*/
protected $headline = '';
/**
* @var string
*/
protected $teaser = '';
/**
* @var string
*/
protected $headerTitle = '';
/**
* @var string
*/
protected $headerSubtitle = '';
/**
* @var string
*/
protected $description = '';
/**
* @var string
*/
protected $descriptionExtended = '';
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference>
*/
protected $images;
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference>
*/
protected $teaserImages;
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference>
*/
protected $headerImages;
public function __construct()
{
$this->initStorageObjects();
}
protected function initStorageObjects()
{
$this->images = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
$this->teaserImages = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
$this->headerImages = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
}
/**
* @return string
*/
public function getDetailPage()
{
return $this->detailPage;
}
/**
* @param string $detailPage
*/
public function setDetailPage($detailPage)
{
$this->detailPage = $detailPage;
}
/**
* @return string
*/
public function getSeason()
{
return $this->season;
}
/**
* @param string $season
*/
public function setSeason($season)
{
$this->season = $season;
}
public function isWinter(): bool
{
return self::SEASON_WINTER === $this->season;
}
public function isSummer(): bool
{
return self::SEASON_SUMMER === $this->season;
}
/**
* @return float $latitude
*/
public function getLatitude()
{
return $this->latitude;
}
/**
* @param float $latitude
*/
public function setLatitude($latitude)
{
$this->latitude = $latitude;
}
/**
* @return float $longitude
*/
public function getLongitude()
{
return $this->longitude;
}
/**
* @param float $longitude
*/
public function setLongitude($longitude)
{
$this->longitude = $longitude;
}
/**
* @return string $name
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* @return string
*/
public function getNameInternal()
{
return $this->nameInternal;
}
/**
* @param string $nameInternal
*/
public function setNameInternal($nameInternal)
{
$this->nameInternal = $nameInternal;
}
/**
* @return string
*/
public function getKeywords()
{
return $this->keywords;
}
/**
* @param string $keywords
*/
public function setKeywords($keywords)
{
$this->keywords = $keywords;
}
/**
* @return string
*/
public function getHeadline()
{
return $this->headline;
}
/**
* @param string $headline
*/
public function setHeadline($headline)
{
$this->headline = $headline;
}
/**
* @return string
*/
public function getTeaser()
{
return $this->teaser;
}
/**
* @param string $teaser
*/
public function setTeaser($teaser)
{
$this->teaser = $teaser;
}
/**
* @return string
*/
public function getHeaderTitle()
{
return $this->headerTitle;
}
/**
* @param string $headerTitle
*/
public function setHeaderTitle($headerTitle)
{
$this->headerTitle = $headerTitle;
}
/**
* @return string
*/
public function getHeaderSubtitle()
{
return $this->headerSubtitle;
}
/**
* @param string $headerSubtitle
*/
public function setHeaderSubtitle($headerSubtitle)
{
$this->headerSubtitle = $headerSubtitle;
}
/**
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* @param string $description
*/
public function setDescription($description)
{
$this->description = $description;
}
/**
* @return string
*/
public function getDescriptionExtended()
{
return $this->descriptionExtended;
}
/**
* @param string $descriptionExtended
*/
public function setDescriptionExtended($descriptionExtended)
{
$this->descriptionExtended = $descriptionExtended;
}
/**
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference> $images
*/
public function getImages()
{
return $this->images;
}
/**
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference> $images
*/
public function setImages(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $images)
{
$this->images = $images;
}
/**
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage
*/
public function getTeaserImages()
{
return $this->teaserImages;
}
/**
* @return null|\TYPO3\CMS\Extbase\Persistence\ObjectStorage
*/
public function getTeaserImage()
{
if ($this->teaserImages->count() === 0) {
return null;
}
return $this->teaserImages->toArray()[0];
}
/**
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $teaserImages
*/
public function setTeaserImages($teaserImages)
{
$this->teaserImages = $teaserImages;
}
/**
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage
*/
public function getHeaderImages()
{
return $this->headerImages;
}
/**
* @return null|\TYPO3\CMS\Extbase\Domain\Model\FileReference
*/
public function getHeaderImage()
{
$headerImages = $this->getHeaderImages();
if ($headerImages->count() === 0) {
return null;
}
return $headerImages->toArray()[0];
}
/**
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $headerImages
*/
public function setHeaderImages($headerImages)
{
$this->headerImages = $headerImages;
}
}
@@ -0,0 +1,97 @@
<?php
namespace EP\EpProducts\Domain\Model;
/***************************************************************
*
* Copyright notice
*
* (c) 2016 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
class Badge extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{
/**
* @var string
*/
protected $title;
/**
* @var string
*/
protected $subtitle;
/**
* @var string
*/
protected $link;
/**
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* @param string $title
*/
public function setTitle($title)
{
$this->title = $title;
}
/**
* @return string
*/
public function getSubtitle()
{
return $this->subtitle;
}
/**
* @param string $subtitle
*/
public function setSubtitle($subtitle)
{
$this->subtitle = $subtitle;
}
/**
* @return string
*/
public function getLink()
{
return $this->link;
}
/**
* @param string $link
*/
public function setLink($link)
{
$this->link = $link;
}
}
@@ -0,0 +1,199 @@
<?php
namespace EP\EpProducts\Domain\Model;
/***************************************************************
*
* Copyright notice
*
* (c) 2016 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
class City extends AbstractDestination implements TeaserInterface
{
/**
* @var bool
*/
protected $excludeFromTeasergroups = false;
/**
* @var string
*/
protected $party = '';
/**
* @var string
*/
protected $leisure = '';
/**
* @var \EP\EpProducts\Domain\Model\Country
*/
protected $country;
/**
* @var \EP\EpProducts\Domain\Model\Region
*/
protected $region;
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\Fact>
*/
protected $facts;
/**
* @var \EP\EpProducts\Domain\Model\Officetip
*/
protected $officetip;
protected function initStorageObjects()
{
parent::initStorageObjects();
$this->facts = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
}
/**
* @return bool
*/
public function isExcludeFromTeasergroups()
{
return $this->excludeFromTeasergroups;
}
/**
* @param bool $excludeFromTeasergroups
*/
public function setExcludeFromTeasergroups($excludeFromTeasergroups)
{
$this->excludeFromTeasergroups = (bool) $excludeFromTeasergroups;
}
/**
* @return string
*/
public function getParty() {
return $this->party;
}
/**
* @param string $party
*/
public function setParty($party) {
$this->party = $party;
}
/**
* @return string
*/
public function getLeisure() {
return $this->leisure;
}
/**
* @param string $leisure
*/
public function setLeisure($leisure) {
$this->leisure = $leisure;
}
/**
* Returns all header images with fallback to parent
* region in case none are assigned.
*
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage
*/
public function getHeaderImages()
{
$headerImages = $this->headerImages;
if ($headerImages->count() === 0 && null !== $this->getRegion()) {
$headerImages = $this->getRegion()->getHeaderImages();
}
return $headerImages;
}
/**
* @return \EP\EpProducts\Domain\Model\Country $country
*/
public function getCountry()
{
return $this->country;
}
/**
* @param \EP\EpProducts\Domain\Model\Country $country
*/
public function setCountry(\EP\EpProducts\Domain\Model\Country $country)
{
$this->country = $country;
}
/**
* @return \EP\EpProducts\Domain\Model\Region $region
*/
public function getRegion()
{
return $this->region;
}
/**
* @param \EP\EpProducts\Domain\Model\Region $region
*/
public function setRegion(\EP\EpProducts\Domain\Model\Region $region)
{
$this->region = $region;
}
/**
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\Fact> $facts
*/
public function getFacts()
{
return $this->facts;
}
/**
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\Fact> $facts
*/
public function setFacts(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $facts)
{
$this->facts = $facts;
}
/**
* @return Officetip
*/
public function getOfficetip()
{
return $this->officetip;
}
/**
* @param Officetip $officetip
*/
public function setOfficetip($officetip)
{
$this->officetip = $officetip;
}
}
@@ -0,0 +1,434 @@
<?php
namespace EP\EpProducts\Domain\Model;
/***************************************************************
*
* Copyright notice
*
* (c) 2016 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
class Concept extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity implements TeaserInterface
{
/**
* @var int
*/
protected $busProId = 0;
/**
* @var string
*/
protected $name = '';
/**
* @var string
*/
protected $code = '';
/**
* @var string
*/
protected $headline = '';
/**
* @var string
*/
protected $headerTitle = '';
/**
* @var string
*/
protected $headerSubtitle = '';
/**
* @var string
*/
protected $teaser = '';
/**
* @var string
*/
protected $popupTitle = 'Hinweis';
/**
* @var string
*/
protected $popupText = '';
/**
* @var string
*/
protected $popupButtonLabel = 'Ok';
/**
* @var string
*/
protected $description = '';
/**
* @var string
*/
protected $descriptionExtended = '';
/**
* @var string
*/
protected $detailPage;
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference>
*/
protected $teaserImages;
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference>
*/
protected $headerImages;
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference>
*/
protected $images;
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\Product>
*/
protected $products;
/**
* __construct
*/
public function __construct()
{
$this->initStorageObjects();
}
/**
*/
protected function initStorageObjects()
{
$this->products = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
$this->teaserImages = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
$this->headerImages = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
$this->images = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
}
/**
* @return int
*/
public function getBusProId() {
return $this->busProId;
}
/**
* @param int $busProId
*/
public function setBusProId($busProId) {
$this->busProId = $busProId;
}
/**
* @return string $name
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* @return string
*/
public function getCode()
{
return $this->code;
}
/**
* @param string $code
*/
public function setCode($code)
{
$this->code = $code;
}
/**
* @return string
*/
public function getTeaser()
{
return $this->teaser;
}
/**
* @param string $teaser
*/
public function setTeaser($teaser)
{
$this->teaser = $teaser;
}
public function getPopupText()
{
return $this->popupText;
}
public function setPopupText($popupText)
{
$this->popupText = $popupText;
return $this;
}
public function getPopupTitle()
{
return $this->popupTitle;
}
public function setPopupTitle($popupTitle)
{
$this->popupTitle = $popupTitle;
return $this;
}
public function getPopupButtonLabel()
{
return $this->popupButtonLabel;
}
public function setPopupButtonLabel($popupButtonLabel)
{
$this->popupButtonLabel = $popupButtonLabel;
return $this;
}
/**
* @return string
*/
public function getHeadline()
{
return $this->headline;
}
/**
* @param string $headline
*/
public function setHeadline($headline)
{
$this->headline = $headline;
}
/**
* @return string
*/
public function getHeaderTitle()
{
return $this->headerTitle;
}
/**
* @param string $headerTitle
*/
public function setHeaderTitle($headerTitle)
{
$this->headerTitle = $headerTitle;
}
/**
* @return string
*/
public function getHeaderSubtitle()
{
return $this->headerSubtitle;
}
/**
* @param string $headerSubtitle
*/
public function setHeaderSubtitle($headerSubtitle)
{
$this->headerSubtitle = $headerSubtitle;
}
/**
* @return string $description
*/
public function getDescription()
{
return $this->description;
}
/**
* @param string $description
*/
public function setDescription($description)
{
$this->description = $description;
}
/**
* @return string
*/
public function getDescriptionExtended()
{
return $this->descriptionExtended;
}
/**
* @param string $descriptionExtended
*/
public function setDescriptionExtended($descriptionExtended)
{
$this->descriptionExtended = $descriptionExtended;
}
/**
* @return string $detailPage
*/
public function getDetailPage()
{
return $this->detailPage;
}
/**
* @param string $detailPage
*/
public function setDetailPage($detailPage)
{
$this->detailPage = $detailPage;
}
/**
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage
*/
public function getTeaserImages()
{
return $this->teaserImages;
}
/**
* @return null|\TYPO3\CMS\Extbase\Persistence\ObjectStorage
*/
public function getTeaserImage()
{
if ($this->teaserImages->count() === 0) {
return null;
}
return $this->teaserImages->toArray()[0];
}
/**
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $teaserImages
*/
public function setTeaserImages($teaserImages)
{
$this->teaserImages = $teaserImages;
}
/**
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage
*/
public function getHeaderImages()
{
return $this->headerImages;
}
/**
* @return null|\TYPO3\CMS\Extbase\Persistence\ObjectStorage
*/
public function getHeaderImage()
{
if ($this->headerImages->count() === 0) {
return null;
}
return $this->headerImages->toArray()[0];
}
/**
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $headerImages
*/
public function setHeaderImages($headerImages)
{
$this->headerImages = $headerImages;
}
/**
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage
*/
public function getImages()
{
return $this->images;
}
/**
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $images
*/
public function setImages($images)
{
$this->images = $images;
}
/**
* @param \EP\EpProducts\Domain\Model\Product $product
*/
public function addProduct(\EP\EpProducts\Domain\Model\Product $product)
{
$this->products->attach($product);
}
/**
* @param \EP\EpProducts\Domain\Model\Product $product
*/
public function removeProduct(\EP\EpProducts\Domain\Model\Product $product)
{
$this->products->detach($product);
}
/**
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\Product>
*/
public function getProducts()
{
return $this->products;
}
/**
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\Product> $products
*/
public function setProducts(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $products)
{
$this->products = $products;
}
}
@@ -0,0 +1,353 @@
<?php
namespace EP\EpProducts\Domain\Model;
/***************************************************************
*
* Copyright notice
*
* (c) 2016 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use CalendR\Event\EventInterface;
use CalendR\Period\PeriodInterface;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
class Contingent extends AbstractEntity implements EventInterface
{
const STATUS_OK = 0;
const STATUS_BLOCKED = 1;
const STATUS_ONREQUEST = 2;
/**
* @var \DateTime
*/
protected $date;
/**
* @var \EP\EpProducts\Domain\Model\Hotel
*/
protected $hotel;
/**
* @var string
*/
protected $roomCode;
/**
* @var string
*/
protected $roomLabel;
/**
* @var int
*/
protected $pax;
/**
* @var int
*/
protected $available;
/**
* @var int
*/
protected $status;
/**
* @var int
*/
protected $minPrice;
/**
* @var int
*/
protected $minNights;
/**
* @var int
*/
protected $additionalNightMinPrice;
/**
* @var int
*/
protected $additionalNightMinNights;
/**
* @param array $data
* @return Contingent
*/
public static function fromArray(array $data)
{
$event = new self;
$event->setPax($data['pax']);
$event->setAvailable($data['available']);
$event->setDate(new \DateTime($data['date']));
$event->setStatus($data['status']);
if ($data['hotel'] instanceof Hotel) {
$event->setHotel($data['hotel']);
}
return $event;
}
/**
* @return \DateTime
*/
public function getDate()
{
return $this->date;
}
/**
* @param \DateTime $date
*/
public function setDate(\DateTime $date)
{
$this->date = $date;
}
/**
* @return Hotel
*/
public function getHotel()
{
return $this->hotel;
}
/**
* @param Hotel $hotel
*/
public function setHotel($hotel)
{
$this->hotel = $hotel;
}
/**
* @return string
*/
public function getRoomCode()
{
return $this->roomCode;
}
/**
* @param string $roomCode
*/
public function setRoomCode($roomCode)
{
$this->roomCode = $roomCode;
}
/**
* @return string
*/
public function getRoomLabel()
{
return $this->roomLabel;
}
/**
* @param string $roomLabel
*/
public function setRoomLabel($roomLabel)
{
$this->roomLabel = $roomLabel;
}
/**
* @return int
*/
public function getPax()
{
return $this->pax;
}
/**
* @param int $pax
*/
public function setPax($pax)
{
$this->pax = $pax;
}
/**
* @return int
*/
public function getAvailable()
{
return $this->available;
}
/**
* @param int $available
*/
public function setAvailable($available)
{
$this->available = $available;
}
/**
* @return int
*/
public function getPercentageAvailable()
{
if ($this->pax === 0) {
return 0;
}
return round($this->available / $this->pax * 100, 2);
}
/**
* @return int
*/
public function getStatus()
{
return $this->status;
}
/**
* @param int $status
*/
public function setStatus($status)
{
$this->status = $status;
}
/**
* @return int
*/
public function getMinPrice()
{
return $this->minPrice;
}
/**
* @param int $minPrice
*/
public function setMinPrice($minPrice)
{
$this->minPrice = $minPrice;
}
/**
* @return int
*/
public function getMinNights()
{
return $this->minNights;
}
/**
* @param int $minNights
*/
public function setMinNights($minNights)
{
$this->minNights = $minNights;
}
/**
* @return int
*/
public function getAdditionalNightMinPrice()
{
return $this->additionalNightMinPrice;
}
/**
* @param int $additionalNightMinPrice
*/
public function setAdditionalNightMinPrice($additionalNightMinPrice)
{
$this->additionalNightMinPrice = $additionalNightMinPrice;
}
/**
* @return int
*/
public function getAdditionalNightMinNights()
{
return $this->additionalNightMinNights;
}
/**
* @param int $additionalNightMinNights
*/
public function setAdditionalNightMinNights($additionalNightMinNights)
{
$this->additionalNightMinNights = $additionalNightMinNights;
}
/**
* @return \DateTime
*/
public function getBegin()
{
return $this->date;
}
/**
* @return \DateTime
*/
public function getEnd()
{
return $this->date;
}
/**
* @param \DateTime $datetime
* @return bool
*/
public function contains(\DateTime $datetime)
{
return $datetime >= $this->getBegin() && $datetime < $this->getEnd();
}
/**
* @param PeriodInterface $period
* @return bool
*/
public function containsPeriod(PeriodInterface $period)
{
return $this->contains($period->getBegin()) && $this->contains($period->getEnd());
}
/**
* @param PeriodInterface $period
* @return bool
*/
public function isDuring(PeriodInterface $period)
{
return $this->getBegin() >= $period->getBegin() && $this->getEnd() < $period->getEnd();
}
/**
* @return int
*/
public function getOccupancy()
{
return $this->getPax() - $this->getAvailable();
}
}
@@ -0,0 +1,158 @@
<?php
namespace EP\EpProducts\Domain\Model;
/***************************************************************
*
* Copyright notice
*
* (c) 2016 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
class Country extends AbstractDestination implements TeaserInterface
{
/**
* @var string
*/
protected $code = '';
/**
* @var string
*/
protected $descriptionExtended = '';
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\Fact>
*/
protected $facts;
/**
* @var \EP\EpProducts\Domain\Model\Officetip
*/
protected $officetip;
/**
* @var \EP\EpProducts\Domain\Model\Snowreport
*/
protected $snowreport;
protected function initStorageObjects()
{
parent::initStorageObjects();
$this->facts = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
}
/**
* @return string
*/
public function getCode() {
return $this->code;
}
/**
* @param string $code
*/
public function setCode($code) {
$this->code = $code;
}
/**
* @return string
*/
public function getDescriptionExtended()
{
return $this->descriptionExtended;
}
/**
* @param string $descriptionExtended
*/
public function setDescriptionExtended($descriptionExtended)
{
$this->descriptionExtended = $descriptionExtended;
}
/**
* @param \EP\EpProducts\Domain\Model\Fact $fact
*/
public function addFact(\EP\EpProducts\Domain\Model\Fact $fact)
{
$this->facts->attach($fact);
}
/**
* @param \EP\EpProducts\Domain\Model\Fact $factToRemove
*/
public function removeFact(\EP\EpProducts\Domain\Model\Fact $factToRemove)
{
$this->facts->detach($factToRemove);
}
/**
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\Fact>
*/
public function getFacts()
{
return $this->facts;
}
/**
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\Fact> $facts
*/
public function setFacts(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $facts)
{
$this->facts = $facts;
}
/**
* @return Officetip
*/
public function getOfficetip()
{
return $this->officetip;
}
/**
* @param Officetip $officetip
*/
public function setOfficetip($officetip)
{
$this->officetip = $officetip;
}
/**
* @return Snowreport
*/
public function getSnowreport()
{
return $this->snowreport;
}
/**
* @param Snowreport $snowreport
*/
public function setSnowreport($snowreport)
{
$this->snowreport = $snowreport;
}
}
@@ -0,0 +1,639 @@
<?php
namespace EP\EpProducts\Domain\Model;
/***************************************************************
*
* Copyright notice
*
* (c) 2016 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
class Date extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{
/**
* @var Product
*/
protected $product;
/**
* @var Hotel
*/
protected $hotel;
/**
* @var Country
*/
protected $country;
/**
* @var Region
*/
protected $region;
/**
* @var City
*/
protected $city;
/**
* @var int
*/
protected $busProId = 0;
/**
* @var int
*/
protected $hotelBusProId = 0;
/**
* @var string
*/
protected $code = '';
/**
* @var bool
*/
protected $daytrip = false;
/**
* @var \DateTime
*/
protected $dateStart;
/**
* @var \DateTime
*/
protected $dateEnd;
/**
* @var int
*/
protected $nights = 0;
/**
* @var string
*/
protected $board = '';
/**
* @var string
*/
protected $boardCode = '';
/**
* @var int
*/
protected $boardBusProId = 0;
/**
* @var bool
*/
protected $busIncluded = false;
/**
* @var bool
*/
protected $skipassIncluded = false;
/**
* @var bool
*/
protected $groupTravel = false;
/**
* @var bool
*/
protected $busAvailable = false;
/**
* @var float
*/
protected $busPrice = 0.0;
/**
* @var string
*/
protected $servicesIncluded = '';
/**
* @var string
*/
protected $servicesGeneral = '';
/**
* @var string
*/
protected $coursesIncluded = '';
/**
* @var string
*/
protected $pickups = '';
/**
* @var float
*/
protected $discount = 0.0;
/**
* @var float
*/
protected $minPrice = 0.0;
/**
* @var float
*/
protected $pseudoPrice = 0.0;
/**
* @var int
*/
protected $available = 0;
/**
* @var int
*/
protected $minPax = 0;
/**
* @var bool
*/
protected $new = false;
/**
* @var string
*/
protected $guide = '';
public function getProduct()
{
return $this->product;
}
public function setProduct($product)
{
$this->product = $product;
}
public function getHotel()
{
return $this->hotel;
}
public function setHotel($hotel)
{
$this->hotel = $hotel;
}
public function getCountry()
{
return $this->country;
}
public function setCountry($country)
{
$this->country = $country;
}
public function getRegion()
{
return $this->region;
}
public function setRegion($region)
{
$this->region = $region;
}
public function getCity()
{
return $this->city;
}
public function setCity($city)
{
$this->city = $city;
}
/**
* @return int $bookingId
*/
public function getBusProId()
{
return $this->busProId;
}
/**
* @param int $busProId
*/
public function setBusProId($busProId)
{
$this->busProId = $busProId;
}
/**
* @return int
*/
public function getHotelBusProId()
{
return $this->hotelBusProId;
}
/**
* @param int $hotelBusProId
*/
public function setHotelBusProId($hotelBusProId)
{
$this->hotelBusProId = $hotelBusProId;
}
/**
* @return string $code
*/
public function getCode()
{
return $this->code;
}
/**
* @param string $code
*/
public function setCode($code)
{
$this->code = $code;
}
/**
* @return bool
*/
public function isDaytrip()
{
return $this->daytrip;
}
/**
* @param bool $daytrip
*/
public function setDaytrip($daytrip)
{
$this->daytrip = $daytrip;
}
/**
* @return \DateTime $dateStart
*/
public function getDateStart()
{
return $this->dateStart;
}
/**
* @param \DateTime $dateStart
*/
public function setDateStart(\DateTime $dateStart)
{
$this->dateStart = $dateStart;
}
/**
* @return \DateTime $dateEnd
*/
public function getDateEnd()
{
return $this->dateEnd;
}
/**
* @param \DateTime $dateEnd
*/
public function setDateEnd(\DateTime $dateEnd)
{
$this->dateEnd = $dateEnd;
}
/**
* @return int
*/
public function getNights()
{
return $this->nights;
}
/**
* @param int $nights
*/
public function setNights($nights)
{
$this->nights = $nights;
}
/**
* @return string
*/
public function getBoard()
{
return $this->board;
}
/**
* @param string $board
*/
public function setBoard($board)
{
$this->board = $board;
}
/**
* @return string
*/
public function getBoardCode()
{
return $this->boardCode;
}
/**
* @param string $boardCode
*/
public function setBoardCode(string $boardCode)
{
$this->boardCode = $boardCode;
}
/**
* @return int
*/
public function getBoardBusProId()
{
return $this->boardBusProId;
}
/**
* @param int $boardBusProId
*/
public function setBoardBusProId(int $boardBusProId)
{
$this->boardBusProId = $boardBusProId;
}
/**
* @return bool $busIncluded
*/
public function getBusIncluded()
{
return $this->busIncluded;
}
/**
* @param bool $busIncluded
*/
public function setBusIncluded($busIncluded)
{
$this->busIncluded = $busIncluded;
}
/**
* @return bool
*/
public function getSkipassIncluded()
{
return $this->skipassIncluded;
}
/**
* @param bool $skipassIncluded
*/
public function setSkipassIncluded($skipassIncluded)
{
$this->skipassIncluded = $skipassIncluded;
}
/**
* @return bool
*/
public function getGroupTravel()
{
return $this->groupTravel;
}
/**
* @param bool $groupTravel
*/
public function setGroupTravel($groupTravel)
{
$this->groupTravel = $groupTravel;
}
/**
* @return bool
*/
public function getBusAvailable()
{
return $this->busAvailable;
}
/**
* @param bool $busAvailable
*/
public function setBusAvailable($busAvailable)
{
$this->busAvailable = $busAvailable;
}
/**
* @return float
*/
public function getBusPrice()
{
return $this->busPrice;
}
/**
* @param float $busPrice
*/
public function setBusPrice($busPrice)
{
$this->busPrice = $busPrice;
}
/**
* @return array $servicesIncluded
*/
public function getServicesIncluded()
{
return unserialize($this->servicesIncluded);
}
/**
* @param array $servicesIncluded
*/
public function setServicesIncluded(array $servicesIncluded)
{
$this->servicesIncluded = serialize($servicesIncluded);
}
/**
* @return array $servicesGeneral
*/
public function getServicesGeneral($token = null)
{
$services = unserialize($this->servicesGeneral);
if (null !== $token) {
return $services[$token] ?? [];
}
return $services;
}
/**
* @param array $servicesGeneral
*/
public function setServicesGeneral(array $servicesGeneral)
{
$this->servicesGeneral = serialize($servicesGeneral);
}
public function getCoursesIncluded()
{
return unserialize($this->coursesIncluded);
}
public function setCoursesIncluded($coursesIncluded)
{
$this->coursesIncluded = $coursesIncluded;
}
public function getActiveCoursesForTravelinfo()
{
return $this->getServicesGeneral('KUR');
}
public function getGuide()
{
return unserialize($this->guide);
}
public function setGuide($guide): Date
{
$this->guide = serialize($guide);
}
/**
* @return string
*/
public function getPickups()
{
return unserialize($this->pickups);
}
/**
* @param array $pickups
*/
public function setPickups(array $pickups)
{
$this->pickups = serialize($pickups);
}
/**
* @return float
*/
public function getDiscount() {
return $this->discount;
}
/**
* @param float $discount
*/
public function setDiscount($discount) {
$this->discount = $discount;
}
/**
* @return float
*/
public function getMinPrice()
{
return $this->minPrice;
}
/**
* @param float $minPrice
*/
public function setMinPrice($minPrice)
{
$this->minPrice = $minPrice;
}
/**
* @return float
*/
public function getPseudoPrice()
{
return $this->pseudoPrice;
}
/**
* @param float $pseudoPrice
*/
public function setPseudoPrice($pseudoPrice)
{
$this->pseudoPrice = $pseudoPrice;
}
/**
* @return int
*/
public function getAvailable()
{
return $this->available;
}
/**
* @param int $available
*/
public function setAvailable($available)
{
$this->available = $available;
}
public function getMinPax()
{
return $this->minPax;
}
public function setMinPax($minPax)
{
$this->minPax = $minPax;
return $this;
}
public function isNew()
{
return $this->new;
}
public function setNew(bool $new)
{
$this->new = $new;
}
}
@@ -0,0 +1,347 @@
<?php
namespace EP\EpProducts\Domain\Model\Dto;
/***************************************************************
*
* 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 FilterOptions implements \JsonSerializable
{
/**
* @var array
*/
public static $priceRangeOptions = [
1 => [ 1, 200 ],
2 => [ 200, 300 ],
3 => [ 300, 400 ],
4 => [ 400, 500 ],
5 => [ 500, 600 ],
6 => [ 600, 999 ],
];
/**
* @var array
*/
protected $priceRanges = [];
/**
* @var array
*/
protected $destinations = [];
/**
* @var array
*/
protected $concepts = [];
/**
* @var array
*/
protected $pax = [];
/**
* @var array
*/
protected $nights = [];
/**
* @var array
*/
protected $hotelTypes = [];
/**
* @var array
*/
protected $boardTypes = [];
/**
* @var array
*/
protected $roomTypes = [];
/**
* @var \DateTime
*/
protected $dateFrom;
/**
* @var \DateTime
*/
protected $dateTo;
/**
* @var bool
*/
protected $busAvailable;
/**
* @var int
*/
protected $resultCount;
/**
* @var string
*/
protected $resultsUri;
public function __construct()
{
$this->pax = [
0 => 'beliebig',
...array_combine(range(1, 24), range(1, 24))
];
}
/**
* @return array
*/
public function getPriceRanges()
{
return $this->priceRanges;
}
/**
* @param array $priceRanges
*/
public function setPriceRanges($priceRanges)
{
$this->priceRanges = $priceRanges;
}
/**
* @return array
*/
public function getDestinations()
{
return $this->destinations;
}
/**
* @param array $destinations
*/
public function setDestinations(array $destinations)
{
$this->destinations = $destinations;
}
/**
* @return array
*/
public function getConcepts()
{
return $this->concepts;
}
/**
* @param array $concepts
*/
public function setConcepts($concepts)
{
$this->concepts = $concepts;
}
/**
* @return array
*/
public function getPax()
{
return $this->pax;
}
/**
* @param array $pax
*/
public function setPax($pax)
{
$this->pax = $pax;
}
/**
* @return array
*/
public function getNights()
{
return $this->nights;
}
/**
* @param array $nights
*/
public function setNights($nights)
{
$this->nights = $nights;
}
/**
* @return array
*/
public function getHotelTypes()
{
return $this->hotelTypes;
}
/**
* @param array $hotelTypes
*/
public function setHotelTypes($hotelTypes)
{
$this->hotelTypes = $hotelTypes;
}
/**
* @return array
*/
public function getBoardTypes()
{
return $this->boardTypes;
}
/**
* @param array $boardTypes
*/
public function setBoardTypes($boardTypes)
{
$this->boardTypes = $boardTypes;
}
/**
* @return array
*/
public function getRoomTypes()
{
return $this->roomTypes;
}
/**
* @param array $roomTypes
*/
public function setRoomTypes($roomTypes)
{
$this->roomTypes = $roomTypes;
}
/**
* @return \DateTime
*/
public function getDateFrom()
{
return $this->dateFrom;
}
/**
* @param \DateTime $dateFrom
*/
public function setDateFrom($dateFrom)
{
$this->dateFrom = $dateFrom;
}
/**
* @return \DateTime
*/
public function getDateTo()
{
return $this->dateTo;
}
/**
* @param \DateTime $dateTo
*/
public function setDateTo($dateTo)
{
$this->dateTo = $dateTo;
}
/**
* @return bool
*/
public function getBusAvailable()
{
return $this->busAvailable;
}
/**
* @param bool $busAvailable
*/
public function setBusAvailable($busAvailable)
{
$this->busAvailable = $busAvailable;
}
/**
* @return int
*/
public function getResultCount(): ?int
{
return $this->resultCount;
}
/**
* @param int $resultCount
*/
public function setResultCount(int $resultCount)
{
$this->resultCount = $resultCount;
}
/**
* @return string
*/
public function getResultsUri(): ?string
{
return $this->resultsUri;
}
/**
* @param string $resultsUri
*/
public function setResultsUri(string $resultsUri)
{
$this->resultsUri = $resultsUri;
}
/**
* @return array
*/
public function jsonSerialize()
{
return [
'priceRanges' => $this->getPriceRanges(),
'destinations' => $this->getDestinations(),
'concepts' => $this->getConcepts(),
'pax' => $this->getPax(),
'nights' => $this->getNights(),
'hotelTypes' => $this->getHotelTypes(),
'boardTypes' => $this->getBoardTypes(),
'roomTypes' => $this->getRoomTypes(),
'dateFrom' => ($this->getDateFrom() !== null) ? $this->getDateFrom()->format('Y-m-d') : null,
'dateTo' => ($this->getDateTo() !== null) ? $this->getDateTo()->format('Y-m-d') : null,
'busAvailable' => $this->getBusAvailable(),
'resultCount' => $this->getResultCount(),
'resultsUri' => $this->getResultsUri(),
];
}
}
@@ -0,0 +1,484 @@
<?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;
}
}
@@ -0,0 +1,113 @@
<?php
namespace EP\EpProducts\Domain\Model\Dto;
use JsonSerializable;
class NewsletterSubscriptionRequest implements JsonSerializable
{
/**
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
*/
private ?string $firstName = null;
/**
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
*/
private ?string $lastName = null;
/**
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
* @TYPO3\CMS\Extbase\Annotation\Validate("EmailAddress")
*/
private ?string $email = null;
/**
* @var list<int>
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
*/
private array $listIds = [];
/**
* @TYPO3\CMS\Extbase\Annotation\Validate("Boolean", options={"is": true})
*/
private bool $consent = false;
public function getFirstName(): ?string
{
return $this->firstName;
}
public function setFirstName(?string $firstName): self
{
$this->firstName = $firstName;
return $this;
}
public function getLastName(): ?string
{
return $this->lastName;
}
public function setLastName(?string $lastName): self
{
$this->lastName = $lastName;
return $this;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(?string $email): self
{
$this->email = $email;
return $this;
}
/**
* @return list<int>
*/
public function getListIds(): array
{
return $this->listIds;
}
/**
* @param list<int|string> $listIds
*/
public function setListIds(array $listIds): self
{
$this->listIds = $listIds;
return $this;
}
public function isConsent(): bool
{
return $this->consent;
}
public function setConsent(bool $consent): self
{
$this->consent = $consent;
return $this;
}
public function jsonSerialize(): array
{
return [
'firstName' => $this->firstName,
'lastName' => $this->lastName,
'email' => $this->email,
'listIds' => array_map(function($value) {
return (int) $value;
}, $this->listIds),
];
}
}
@@ -0,0 +1,96 @@
<?php
namespace EP\EpProducts\Domain\Model;
/***************************************************************
*
* Copyright notice
*
* (c) 2016 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
class Fact extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{
/**
* @var string
*/
protected $name = '';
/**
* @var string
*/
protected $keywords = '';
/**
* @var string
*/
protected $label = '';
/**
* @return string $name
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* @return string $keywords
*/
public function getKeywords()
{
return $this->keywords;
}
/**
* @param string $keywords
*/
public function setKeywords($keywords)
{
$this->keywords = $keywords;
}
/**
* @return string
*/
public function getLabel()
{
return $this->label;
}
/**
* @param string $label
*/
public function setLabel($label)
{
$this->label = $label;
}
}
@@ -0,0 +1,75 @@
<?php
namespace EP\EpProducts\Domain\Model;
/***************************************************************
*
* Copyright notice
*
* (c) 2016 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
class Faq extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{
/**
* @var string
*/
protected $question = '';
/**
* @var string
*/
protected $answer = '';
/**
* @return string $question
*/
public function getQuestion()
{
return $this->question;
}
/**
* @param string $question
*/
public function setQuestion($question)
{
$this->question = $question;
}
/**
* @return string $answer
*/
public function getAnswer()
{
return $this->answer;
}
/**
* @param string $answer
*/
public function setAnswer($answer)
{
$this->answer = $answer;
}
}
@@ -0,0 +1,111 @@
<?php
namespace EP\EpProducts\Domain\Model;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
/***************************************************************
*
* 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 GroupsPriceBoard extends AbstractEntity implements \JsonSerializable
{
/**
* @var string
*/
protected $title;
/**
* @var float
*/
protected $price;
/**
* @var float
*/
protected $priceChf;
/**
* @return string
*/
public function getTitle(): string
{
return $this->title;
}
/**
* @param string $title
*/
public function setTitle(string $title): void
{
$this->title = $title;
}
/**
* @return float
*/
public function getPrice(): float
{
return $this->price;
}
/**
* @param float $price
*/
public function setPrice(float $price): void
{
$this->price = $price;
}
/**
* @return float
*/
public function getPriceChf(): ?float
{
return $this->priceChf;
}
/**
* @param float $price
*/
public function setPriceChf(float $price): void
{
$this->priceChf = $price;
}
/**
* @return array
*/
public function jsonSerialize(): array
{
return [
'uid' => $this->getUid(),
'title' => $this->getTitle(),
'price' => [
'EUR' => $this->getPrice(),
'CHF' => $this->getPriceChf(),
],
];
}
}
@@ -0,0 +1,201 @@
<?php
namespace EP\EpProducts\Domain\Model;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
/***************************************************************
*
* 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 GroupsPriceConfig extends AbstractEntity implements \JsonSerializable
{
/**
* @var \DateTime
*/
protected $dateFrom;
/**
* @var \DateTime
*/
protected $dateTo;
/**
* @var int
*/
protected $personsIncluded;
/**
* @var float
*/
protected $price;
/**
* @var float
*/
protected $priceChf;
/**
* @var float
*/
protected $priceAdditionalPerson;
/**
* @var float
*/
protected $priceAdditionalPersonChf;
/**
* @return \DateTime
*/
public function getDateFrom(): \DateTime
{
return $this->dateFrom;
}
/**
* @param \DateTime $dateFrom
*/
public function setDateFrom(\DateTime $dateFrom): void
{
$this->dateFrom = $dateFrom;
}
/**
* @return \DateTime
*/
public function getDateTo(): \DateTime
{
return $this->dateTo;
}
/**
* @param \DateTime $dateTo
*/
public function setDateTo(\DateTime $dateTo): void
{
$this->dateTo = $dateTo;
}
/**
* @return int
*/
public function getPersonsIncluded(): int
{
return $this->personsIncluded;
}
/**
* @param int $personsIncluded
*/
public function setPersonsIncluded(int $personsIncluded): void
{
$this->personsIncluded = $personsIncluded;
}
/**
* @return float
*/
public function getPrice(): float
{
return $this->price;
}
/**
* @param float $price
*/
public function setPrice(float $price): void
{
$this->price = $price;
}
/**
* @return float
*/
public function getPriceChf(): ?float
{
return $this->priceChf;
}
/**
* @param float $price
*/
public function setPriceChf(float $price): void
{
$this->priceChf = $price;
}
/**
* @return float
*/
public function getPriceAdditionalPerson(): ?float
{
return $this->priceAdditionalPerson;
}
/**
* @param float $priceAdditionalPerson
*/
public function setPriceAdditionalPerson(float $priceAdditionalPerson): void
{
$this->priceAdditionalPerson = $priceAdditionalPerson;
}
/**
* @return float
*/
public function getPriceAdditionalPersonChf(): ?float
{
return $this->priceAdditionalPersonChf;
}
/**
* @param float $priceAdditionalPerson
*/
public function setPriceAdditionalPersonChf(float $priceAdditionalPerson): void
{
$this->priceAdditionalPersonChf = $priceAdditionalPerson;
}
/**
* @return array
*/
public function jsonSerialize(): array
{
return [
'uid' => $this->getUid(),
'dateFrom' => $this->getDateFrom()->format('Y-m-d'),
'dateTo' => $this->getDateTo()->format('Y-m-d'),
'personsIncluded' => $this->getPersonsIncluded(),
'price' => [
'EUR' => $this->getPrice(),
'CHF' => $this->getPriceChf(),
],
'priceAdditionalPerson' => [
'EUR' => $this->getPriceAdditionalPerson(),
'CHF' => $this->getPriceAdditionalPersonChf(),
],
];
}
}
@@ -0,0 +1,160 @@
<?php
namespace EP\EpProducts\Domain\Model;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
/***************************************************************
*
* 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 GroupsPriceOption extends AbstractEntity implements \JsonSerializable
{
const TYPE_GLOBAL = 1;
const TYPE_PER_PAX = 2;
const TYPE_PER_NIGHT = 3;
const TYPE_PER_PAX_AND_NIGHT = 4;
/**
* @var string
*/
protected $title;
/**
* @var float
*/
protected $price;
/**
* @var float
*/
protected $priceChf;
/**
* @var int
*/
protected $type;
/**
* @var bool
*/
protected $ignoreWithBoard = false;
/**
* @return string
*/
public function getTitle(): string
{
return $this->title;
}
/**
* @param string $title
*/
public function setTitle(string $title): void
{
$this->title = $title;
}
/**
* @return float
*/
public function getPrice(): float
{
return $this->price;
}
/**
* @param float $price
*/
public function setPrice(float $price): void
{
$this->price = $price;
}
/**
* @return float
*/
public function getPriceChf(): ?float
{
return $this->priceChf;
}
/**
* @param float $price
*/
public function setPriceChf(float $price): void
{
$this->priceChf = $price;
}
/**
* @return int
*/
public function getType(): int
{
return $this->type;
}
/**
* @param int $type
*/
public function setType(int $type): void
{
$this->type = $type;
}
/**
* @return bool
*/
public function isIgnoreWithBoard(): bool
{
return $this->ignoreWithBoard;
}
/**
* @param bool $ignoreWithBoard
*/
public function setIgnoreWithBoard(bool $ignoreWithBoard): void
{
$this->ignoreWithBoard = $ignoreWithBoard;
}
/**
* @return array
*/
public function jsonSerialize(): array
{
return [
'uid' => $this->getUid(),
'title' => $this->getTitle(),
'price' => [
'EUR' => $this->getPrice(),
'CHF' => $this->getPriceChf(),
],
'type' => $this->getType(),
'ignoreWithBoard' => $this->isIgnoreWithBoard(),
];
}
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,73 @@
<?php
namespace EP\EpProducts\Domain\Model;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
class Infobox extends AbstractEntity
{
/**
* @var string
*/
protected $title;
/**
* @var string
*/
protected $text;
/**
* @var bool
*/
protected $defaultText;
/**
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* @param string $title
*/
public function setTitle($title)
{
$this->title = $title;
}
/**
* @return string
*/
public function getText()
{
return $this->text;
}
/**
* @param string $text
*/
public function setText($text)
{
$this->text = $text;
}
/**
* @return bool
*/
public function isDefaultText()
{
return $this->defaultText;
}
/**
* @param bool $defaultText
*/
public function setDefaultText($defaultText)
{
$this->defaultText = $defaultText;
}
}
@@ -0,0 +1,117 @@
<?php
namespace EP\EpProducts\Domain\Model;
/***************************************************************
*
* Copyright notice
*
* (c) 2016 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
class Journey extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{
/**
* @var string
*/
protected $name = '';
/**
* @var string
*/
protected $byCar = '';
/**
* @var string
*/
protected $byBus;
/**
* @var \TYPO3\CMS\Extbase\Domain\Model\FileReference
*/
protected $image;
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* @return string
*/
public function getByCar()
{
return $this->byCar;
}
/**
* @param string $byCar
*/
public function setByCar($byCar)
{
$this->byCar = $byCar;
}
/**
* @return string
*/
public function getByBus()
{
return $this->byBus;
}
/**
* @param string $byBus
*/
public function setByBus($byBus)
{
$this->byBus = $byBus;
}
/**
* @return \TYPO3\CMS\Extbase\Domain\Model\FileReference
*/
public function getImage()
{
return $this->image;
}
/**
* @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $image
*/
public function setImage($image)
{
$this->image = $image;
}
}
@@ -0,0 +1,54 @@
<?php
namespace EP\EpProducts\Domain\Model;
/***************************************************************
*
* Copyright notice
*
* (c) 2016 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
class MatchCode extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{
/**
* @var string
*/
protected $code = '';
/**
* @return string
*/
public function getCode()
{
return $this->code;
}
/**
* @param string $code
*/
public function setCode($code)
{
$this->code = $code;
}
}
@@ -0,0 +1,96 @@
<?php
namespace EP\EpProducts\Domain\Model;
/***************************************************************
*
* Copyright notice
*
* (c) 2016 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
class Officetip extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{
/**
* @var string
*/
protected $label = '';
/**
* @var string
*/
protected $text = '';
/**
* @var \EP\EpProducts\Domain\Model\Teammember
*/
protected $author;
/**
* @return string
*/
public function getLabel()
{
return $this->label;
}
/**
* @param string $label
*/
public function setLabel($label)
{
$this->label = $label;
}
/**
* @return string $text
*/
public function getText()
{
return $this->text;
}
/**
* @param string $text
*/
public function setText($text)
{
$this->text = $text;
}
/**
* @return Teammember $author
*/
public function getAuthor()
{
return $this->author;
}
/**
* @param Teammember $author
*/
public function setAuthor(Teammember $author)
{
$this->author = $author;
}
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,476 @@
<?php
namespace EP\EpProducts\Domain\Model;
/***************************************************************
*
* Copyright notice
*
* (c) 2016 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
class Region extends AbstractDestination implements TeaserInterface
{
/**
* @var bool
*/
protected $excludeFromTeasergroups = false;
/**
* @var string
*/
protected $skiArea = '';
/**
* @var string
*/
protected $skiAreaExtended = '';
/**
* @var string
*/
protected $skiPass = '';
/**
* @var string
*/
protected $news = '';
/**
* @var string
*/
protected $length = '';
/**
* @var string
*/
protected $height = '';
/**
* @var string
*/
protected $lifts = '';
/**
* @var string
*/
protected $feature = '';
/**
* @var \EP\EpProducts\Domain\Model\Country
*/
protected $country;
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\City>
* @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove")
*/
protected $cities;
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\Product>
* @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove")
*/
protected $products;
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\Fact>
*/
protected $facts;
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\Hotel>
* @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove")
*/
protected $hotels;
/**
* @var \EP\EpProducts\Domain\Model\Snowreport
*/
protected $snowreport;
/**
* @var \EP\EpProducts\Domain\Model\Webcam
*/
protected $webcam;
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference>
*/
protected $regionMaps;
/**
* @var \TYPO3\CMS\Extbase\Domain\Model\FileReference
*/
protected $awardImage;
/**
* @var string
*/
protected $awardLink;
/**
* @var string
*/
protected $awardLabel;
protected function initStorageObjects()
{
parent::initStorageObjects();
$this->cities = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
$this->products = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
$this->facts = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
$this->hotels = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
$this->regionMaps = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
}
/**
* @return bool
*/
public function isExcludeFromTeasergroups()
{
return $this->excludeFromTeasergroups;
}
/**
* @param bool $excludeFromTeasergroups
*/
public function setExcludeFromTeasergroups($excludeFromTeasergroups)
{
$this->excludeFromTeasergroups = (bool) $excludeFromTeasergroups;
}
/**
* @return string
*/
public function getSkiArea() {
return $this->skiArea;
}
/**
* @param string $skiArea
*/
public function setSkiArea($skiArea) {
$this->skiArea = $skiArea;
}
/**
* @return string
*/
public function getSkiAreaExtended()
{
return $this->skiAreaExtended;
}
/**
* @param string $skiAreaExtended
*/
public function setSkiAreaExtended($skiAreaExtended)
{
$this->skiAreaExtended = $skiAreaExtended;
}
/**
* @return string
*/
public function getSkiPass() {
return $this->skiPass;
}
/**
* @param string $skiPass
*/
public function setSkiPass($skiPass) {
$this->skiPass = $skiPass;
}
/**
* @return string
*/
public function getNews() {
return $this->news;
}
/**
* @param string $news
*/
public function setNews($news) {
$this->news = $news;
}
/**
* @return string
*/
public function getLength() {
return $this->length;
}
/**
* @param string $length
*/
public function setLength($length) {
$this->length = $length;
}
/**
* @return string
*/
public function getHeight() {
return $this->height;
}
/**
* @param string $height
*/
public function setHeight($height) {
$this->height = $height;
}
/**
* @return string
*/
public function getLifts() {
return $this->lifts;
}
/**
* @param string $lifts
*/
public function setLifts($lifts) {
$this->lifts = $lifts;
}
/**
* @return string
*/
public function getFeature()
{
return $this->feature;
}
/**
* @param string $feature
*/
public function setFeature($feature)
{
$this->feature = $feature;
}
/**
* Returns all header images with fallback to parent
* country in case none are assigned.
*
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage
*/
public function getHeaderImages()
{
$headerImages = $this->headerImages;
if ($headerImages->count() === 0 && null !== $this->getCountry()) {
$headerImages = $this->getCountry()->getHeaderImages();
}
return $headerImages;
}
/**
* @return \EP\EpProducts\Domain\Model\Country $country
*/
public function getCountry()
{
return $this->country;
}
/**
* @param \EP\EpProducts\Domain\Model\Country $country
*/
public function setCountry(\EP\EpProducts\Domain\Model\Country $country)
{
$this->country = $country;
}
/**
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage
*/
public function getCities() {
return $this->cities;
}
/**
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $cities
*/
public function setCities($cities) {
$this->cities = $cities;
}
/**
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage
*/
public function getProducts() {
return $this->products;
}
/**
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $products
*/
public function setProducts($products) {
$this->products = $products;
}
/**
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\Fact> $facts
*/
public function getFacts()
{
return $this->facts;
}
/**
* Sets the facts
*
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\Fact> $facts
*/
public function setFacts(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $facts)
{
$this->facts = $facts;
}
/**
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage
*/
public function getHotels() {
return $this->hotels;
}
/**
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $hotels
*/
public function setHotels($hotels) {
$this->hotels = $hotels;
}
/**
* @return Snowreport
*/
public function getSnowreport()
{
return $this->snowreport;
}
/**
* @param Snowreport $snowreport
*/
public function setSnowreport($snowreport)
{
$this->snowreport = $snowreport;
}
/**
* @return Webcam
*/
public function getWebcam()
{
return $this->webcam;
}
/**
* @return bool
*/
public function getWebcamAvailable()
{
$webcam = $this->getWebcam();
return $webcam !== null && $webcam->getAvailable();
}
/**
* @param Webcam $webcam
*/
public function setWebcam($webcam)
{
$this->webcam = $webcam;
}
/**
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference>
*/
public function getRegionMaps()
{
return $this->regionMaps;
}
/**
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference>
*/
public function setRegionMaps($regionMaps)
{
$this->regionMaps = $regionMaps;
}
/**
* @return \TYPO3\CMS\Extbase\Domain\Model\FileReference
*/
public function getAwardImage()
{
return $this->awardImage;
}
/**
* @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $awardImage
*/
public function setAwardImage($awardImage)
{
$this->awardImage = $awardImage;
}
/**
* @return string
*/
public function getAwardLink()
{
return $this->awardLink;
}
/**
* @param string $awardLink
*/
public function setAwardLink($awardLink)
{
$this->awardLink = $awardLink;
}
/**
* @return string
*/
public function getAwardLabel()
{
return $this->awardLabel;
}
/**
* @param string $awardLabel
*/
public function setAwardLabel($awardLabel)
{
$this->awardLabel = $awardLabel;
}
}
@@ -0,0 +1,127 @@
<?php
namespace EP\EpProducts\Domain\Model;
use TYPO3\CMS\Extbase\Annotation\ORM\Lazy;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
/***************************************************************
*
* 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 Reseller extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{
/**
* @var string
*/
protected $name;
/**
* @var string
*/
protected $code;
/**
* @var string
*/
protected $paCode;
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\Product>
* @Lazy()
*/
protected $products;
public function __construct()
{
$this->products = new ObjectStorage();
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* @return string
*/
public function getCode()
{
return $this->code;
}
/**
* @param string $code
*/
public function setCode($code)
{
$this->code = $code;
}
/**
* @return string
*/
public function getPaCode()
{
return $this->paCode;
}
/**
* @param string $paCode
*/
public function setPaCode($paCode)
{
$this->paCode = $paCode;
}
/**
* @return ObjectStorage
*/
public function getProducts()
{
return $this->products;
}
/**
* @param ObjectStorage $products
*/
public function setProducts($products)
{
$this->products = $products;
}
}
@@ -0,0 +1,48 @@
<?php
namespace EP\EpProducts\Domain\Model;
/***************************************************************
*
* Copyright notice
*
* (c) 2016 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
class Room
{
const ROOM_TYPE_UNCLASSIFIED = 0;
const ROOM_TYPE_FOR_ONE = 1;
const ROOM_TYPE_FOR_TWO = 2;
const ROOM_TYPE_FOR_THREE = 3;
const ROOM_TYPE_FOR_FOUR = 4;
const ROOM_TYPE_FOR_FIVE = 5;
const ROOM_TYPE_FOR_SIX = 6;
const ROOM_TYPE_FOR_SEVEN = 7;
const ROOM_TYPE_FOR_EIGHT = 8;
const ROOM_TYPE_FOR_NINE_PLUS = 9;
const ROOM_TYPE_WITH_OTHERS = 10;
const ROOM_STATUS_AVAILABLE = 1;
const ROOM_STATUS_ON_REQUEST = 2;
const ROOM_STATUS_FULLY_BOOKED = 3;
}
@@ -0,0 +1,85 @@
<?php
namespace EP\EpProducts\Domain\Model;
/***************************************************************
*
* Copyright notice
*
* (c) 2016 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
class SearchResult
{
/**
* @var int
*/
protected $total = 0;
/**
* @var array
*/
protected $data = [];
/**
* @param array $data
* @param int $total
*/
public function __construct(array $data = [], $total = 0)
{
$this->data = $data;
$this->total = $total;
}
/**
* @return int
*/
public function getTotal()
{
return $this->total;
}
/**
* @param int $total
*/
public function setTotal($total)
{
$this->total = $total;
}
/**
* @return array
*/
public function getData()
{
return $this->data;
}
/**
* @param array $data
*/
public function setData($data)
{
$this->data = $data;
}
}
@@ -0,0 +1,392 @@
<?php
namespace EP\EpProducts\Domain\Model;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
/***************************************************************
*
* 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 Snowreport extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{
/**
* @var int
*/
protected $vendorUid;
/**
* @var string
*/
protected $regionName = '';
/**
* @var bool
*/
protected $glacier = false;
/**
* @var int
*/
protected $heightMax = 0;
/**
* @var int
*/
protected $heightMin = 0;
/**
* @var bool
*/
protected $opened = false;
/**
* @var int
*/
protected $snowLevelMountain = 0;
/**
* @var int
*/
protected $snowLevelValley = 0;
/**
* @var string
*/
protected $snowQuality = '';
/**
* @var \DateTime
*/
protected $lastSnowfall;
/**
* @var int
*/
protected $liftsTotal = 0;
/**
* @var int
*/
protected $liftsOpened = 0;
/**
* @var \DateTime
*/
protected $lastUpdate;
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\Webcam>
*/
protected $webcams;
/**
* @var \DateTime
*/
protected $seasonStart;
/**
* @var \DateTime
*/
protected $seasonEnd;
public function __construct()
{
$this->webcams = new ObjectStorage();
}
/**
* @return int
*/
public function getVendorUid()
{
return $this->vendorUid;
}
/**
* @param int $vendorUid
*/
public function setVendorUid($vendorUid)
{
$this->vendorUid = $vendorUid;
}
/**
* @return string
*/
public function getRegionName()
{
return $this->regionName;
}
/**
* @param string $regionName
*/
public function setRegionName($regionName)
{
$this->regionName = $regionName;
}
/**
* @return bool
*/
public function getGlacier()
{
return $this->glacier;
}
/**
* @param bool $glacier
*/
public function setGlacier($glacier)
{
$this->glacier = $glacier;
}
/**
* @return int
*/
public function getHeightMax()
{
return $this->heightMax;
}
/**
* @param int $heightMax
*/
public function setHeightMax($heightMax)
{
$this->heightMax = $heightMax;
}
/**
* @return int
*/
public function getHeightMin()
{
return $this->heightMin;
}
/**
* @param int $heightMin
*/
public function setHeightMin($heightMin)
{
$this->heightMin = $heightMin;
}
/**
* @return bool
*/
public function getOpened()
{
return $this->opened;
}
/**
* @param bool $opened
*/
public function setOpened($opened)
{
$this->opened = $opened;
}
/**
* @return int
*/
public function getSnowLevelMountain()
{
return $this->snowLevelMountain;
}
/**
* @param int $snowLevelMountain
*/
public function setSnowLevelMountain($snowLevelMountain)
{
$this->snowLevelMountain = $snowLevelMountain;
}
/**
* @return int
*/
public function getSnowLevelValley()
{
return $this->snowLevelValley;
}
/**
* @param int $snowLevelValley
*/
public function setSnowLevelValley($snowLevelValley)
{
$this->snowLevelValley = $snowLevelValley;
}
/**
* @return string
*/
public function getSnowQuality()
{
return $this->snowQuality;
}
/**
* @param string $snowQuality
*/
public function setSnowQuality($snowQuality)
{
$this->snowQuality = $snowQuality;
}
/**
* @return \DateTime
*/
public function getLastSnowfall()
{
return $this->lastSnowfall;
}
/**
* @param \DateTime $lastSnowfall
*/
public function setLastSnowfall($lastSnowfall)
{
$this->lastSnowfall = $lastSnowfall;
}
/**
* @return int
*/
public function getLiftsTotal()
{
return (int) $this->liftsTotal;
}
/**
* @param int $liftsTotal
*/
public function setLiftsTotal($liftsTotal)
{
$this->liftsTotal = $liftsTotal;
}
/**
* @return int
*/
public function getLiftsOpened()
{
return (int) $this->liftsOpened;
}
/**
* @param int $liftsOpened
*/
public function setLiftsOpened($liftsOpened)
{
$this->liftsOpened = $liftsOpened;
}
/**
* @return \DateTime
*/
public function getLastUpdate()
{
return $this->lastUpdate;
}
/**
* @param \DateTime $lastUpdate
*/
public function setLastUpdate($lastUpdate)
{
$this->lastUpdate = $lastUpdate;
}
/**
* @param \EP\EpProducts\Domain\Model\Webcam $webcam
*/
public function addWebcam(\EP\EpProducts\Domain\Model\Webcam $webcam)
{
$this->webcams->attach($webcam);
}
/**
* @param \EP\EpProducts\Domain\Model\Webcam $webcam
*/
public function removeWebcam(\EP\EpProducts\Domain\Model\Webcam $webcam)
{
$this->webcams->detach($webcam);
}
/**
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\Webcam>
*/
public function getWebcams()
{
return $this->webcams;
}
/**
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\Webcam> $webcams
*/
public function setWebcams(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $webcams)
{
$this->webcams = $webcams;
}
/**
* @return \DateTime
*/
public function getSeasonStart()
{
return $this->seasonStart;
}
/**
* @param \DateTime $seasonStart
*/
public function setSeasonStart($seasonStart)
{
$this->seasonStart = $seasonStart;
}
/**
* @return \DateTime
*/
public function getSeasonEnd()
{
return $this->seasonEnd;
}
/**
* @param \DateTime $seasonEnd
*/
public function setSeasonEnd($seasonEnd)
{
$this->seasonEnd = $seasonEnd;
}
}
@@ -0,0 +1,187 @@
<?php
namespace EP\EpProducts\Domain\Model;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
/***************************************************************
*
* 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 Teammember extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{
/**
* @var string
*/
protected $name = '';
/**
* @var string
*/
protected $email = '';
/**
* @var string
*/
protected $phone = '';
/**
* @var string
*/
protected $tasks = '';
/**
* @var \TYPO3\CMS\Extbase\Domain\Model\FileReference
*/
protected $image;
/**
* @var string
*/
protected $description = '';
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\Category>
*/
protected $categories;
public function __construct()
{
$this->categories = new ObjectStorage();
}
/**
* @return string $name
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* @return string $email
*/
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 getTasks()
{
return $this->tasks;
}
/**
* @param string $tasks
*/
public function setTasks($tasks)
{
$this->tasks = $tasks;
}
/**
* @return \TYPO3\CMS\Extbase\Domain\Model\FileReference
*/
public function getImage()
{
return $this->image;
}
/**
* @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $image
*/
public function setImage($image)
{
$this->image = $image;
}
/**
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* @param string $description
*/
public function setDescription($description)
{
$this->description = $description;
}
/**
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\Category>
*/
public function getCategories()
{
return $this->categories;
}
/**
* @param ObjectStorage $categories
*/
public function setCategories($categories)
{
$this->categories = $categories;
}
}
@@ -0,0 +1,50 @@
<?php
namespace EP\EpProducts\Domain\Model;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
/***************************************************************
*
* 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!
***************************************************************/
interface TeaserInterface
{
/**
* @return string
*/
public function getTeaser();
/**
* @return ObjectStorage
*/
public function getTeaserImages();
/**
* @return null|\TYPO3\CMS\Extbase\Persistence\ObjectStorage
*/
public function getTeaserImage();
}
@@ -0,0 +1,329 @@
<?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;
}
}
@@ -0,0 +1,61 @@
<?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;
}
}
@@ -0,0 +1,76 @@
<?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;
}
}
@@ -0,0 +1,138 @@
<?php
namespace EP\EpProducts\Domain\Model;
/***************************************************************
*
* Copyright notice
*
* (c) 2016 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
class Webcam extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{
/**
* @var int
*/
protected $vendorUid;
/**
* @var \EP\EpProducts\Domain\Model\Snowreport
*/
protected $snowreport;
/**
* @var string
*/
protected $name;
/**
* @var string
*/
protected $url;
/**
* @var bool
*/
protected $available = true;
/**
* @return Snowreport
*/
public function getSnowreport()
{
return $this->snowreport;
}
/**
* @param Snowreport $snowreport
*/
public function setSnowreport($snowreport)
{
$this->snowreport = $snowreport;
}
/**
* @return int
*/
public function getVendorUid()
{
return $this->vendorUid;
}
/**
* @param int $vendorUid
*/
public function setVendorUid($vendorUid)
{
$this->vendorUid = $vendorUid;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* @return string
*/
public function getUrl()
{
return $this->url;
}
/**
* @param string $url
*/
public function setUrl($url)
{
$this->url = $url;
}
/**
* @return boolean
*/
public function getAvailable()
{
return $this->available;
}
/**
* @param boolean $available
*/
public function setAvailable($available)
{
$this->available = $available;
}
}
@@ -0,0 +1,230 @@
<?php
namespace EP\EpProducts\Domain\Repository;
use EP\EpProducts\Domain\Model\Dto\FilterOptions;
use EP\EpProducts\Service\FilterService;
use EP\EpProducts\Traits\DbConnectionTrait;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
use TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings;
use TYPO3\CMS\Extbase\Persistence\Repository;
abstract class AbstractRepository extends Repository
{
use DbConnectionTrait;
public function initializeObject(): void
{
/** @var $querySettings \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings */
$querySettings = $this->objectManager->get(Typo3QuerySettings::class);
$querySettings->setRespectStoragePage(false);
$this->setDefaultQuerySettings($querySettings);
}
/**
* @param array $uids
* @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
*/
public function getListByUids(array $uids = [])
{
$query = $this->createQuery();
$query->matching(
$query->in('uid', $uids)
);
return $query->execute();
}
protected function addFiltersettingsConditions
(
QueryBuilder $qb,
array $filterSettings,
bool $constraintDates = true
): void {
if ($constraintDates) {
$this->addDateFilterConditions($qb, $filterSettings);
}
$this->addPriceRangeFilterConditions($qb, $filterSettings);
$this->addCountryRegionAndCityFilterConditions($qb, $filterSettings);
$this->addConceptFilterConditions($qb, $filterSettings);
$this->addPaxFilterConditions($qb, $filterSettings);
$this->addDurationFilterConditions($qb, $filterSettings);
$this->addHotelTypesFilterConditions($qb, $filterSettings);
$this->addBoardTypesFilterConditions($qb, $filterSettings);
$this->addRoomTypesFilterConditions($qb, $filterSettings);
$this->addTransportationFilterConditions($qb, $filterSettings);
// Product
if (!empty($filterSettings['productUid'])) {
$qb->andWhere($qb->expr()->eq(
'date.product',
$qb->createNamedParameter((int)$filterSettings['productUid'], Connection::PARAM_INT)
));
}
// Hotel
if (!empty($filterSettings['hotelUid'])) {
$qb->andWhere($qb->expr()->eq(
'date.hotel',
$qb->createNamedParameter((int)$filterSettings['hotelUid'], Connection::PARAM_INT)
));
}
}
protected function addDateFilterConditions(QueryBuilder $qb, array $filterSettings): void
{
// Date Start
if (!empty($filterSettings['dateFrom'])) {
$qb->andWhere($qb->expr()->gte(
'date.date_start',
$qb->createNamedParameter($filterSettings['dateFrom'])
));
}
// Date End
if (!empty($filterSettings['dateTo'])) {
$qb->andWhere($qb->expr()->lte(
'date.date_end',
$qb->createNamedParameter($filterSettings['dateTo'])
));
}
}
protected function addHotelFilterConditions(QueryBuilder $qb, array $filterSettings): void
{
// Hotel
if ($filterSettings['hotelUid'] > 0) {
$qb->andWhere($qb->expr()->eq(
'date.hotel',
$qb->createNamedParameter((int)$filterSettings['hotelUid'], Connection::PARAM_INT)
));
}
// Hotel types
if (isset($filterSettings['hotelTypes']) && is_array($filterSettings['hotelTypes']) && count($filterSettings['hotelTypes']) > 0) {
$qb->andWhere($qb->expr()->in(
'date.hotel_type',
$qb->createNamedParameter($filterSettings['hotelTypes'], Connection::PARAM_INT_ARRAY)
));
}
}
protected function addCountryRegionAndCityFilterConditions(QueryBuilder $qb, array $filterSettings): void
{
foreach (['city', 'region', 'country'] as $column) {
$key = $column . 'Uids';
if (isset($filterSettings[$key]) && is_array($filterSettings[$key]) && count($filterSettings[$key]) > 0) {
$qb->andWhere($qb->expr()->in(
'date.' . $column,
$qb->createNamedParameter($filterSettings[$key], Connection::PARAM_INT_ARRAY)
));
break;
}
}
}
protected function addConceptFilterConditions(QueryBuilder $qb, array $filterSettings): void
{
if (isset($filterSettings['conceptUids']) && is_array($filterSettings['conceptUids']) && count($filterSettings['conceptUids']) > 0) {
$qb->andWhere($qb->expr()->in(
'date.concept',
$qb->createNamedParameter($filterSettings['conceptUids'], Connection::PARAM_INT_ARRAY)
));
}
}
protected function addPaxFilterConditions(QueryBuilder $qb, array $filterSettings): void
{
// Pax
if ($filterSettings['pax'] > 0) {
$qb->andWhere($qb->expr()->lte(
'date.min_pax',
$qb->createNamedParameter($filterSettings['pax'], Connection::PARAM_INT)
));
}
}
protected function addPriceRangeFilterConditions(QueryBuilder $qb, array $filterSettings): void
{
// Price ranges
if (isset($filterSettings['priceRanges']) && is_array($filterSettings['priceRanges']) && count($filterSettings['priceRanges']) > 0) {
$orX = $qb->expr()->orX();
foreach ($filterSettings['priceRanges'] as $priceRange) {
[ $priceMin, $priceMax ] = FilterOptions::$priceRangeOptions[$priceRange];
$orX->add($qb->expr()->andX(
$qb->expr()->gte(
'date.min_price',
$qb->createNamedParameter($priceMin, Connection::PARAM_INT)
),
$qb->expr()->lt(
'date.min_price',
$qb->createNamedParameter($priceMax, Connection::PARAM_INT)
)
));
}
$qb->andWhere($orX);
}
}
protected function addDurationFilterConditions(QueryBuilder $qb, array $filterSettings): void
{
// Duration
if (0 === $filterSettings['nights']) {
return;
}
$nights = $filterSettings['nights'];
if ($nights === FilterService::DURATION_SHORT) {
$qb->andWhere($qb->expr()->lte(
'date.nights',
$qb->createNamedParameter($nights, Connection::PARAM_INT))
);
} elseif ($nights === FilterService::DURATION_LONG) {
$qb->andWhere($qb->expr()->gte(
'date.nights',
$qb->createNamedParameter($nights, Connection::PARAM_INT))
);
}
}
protected function addHotelTypesFilterConditions(QueryBuilder $qb, array $filterSettings): void
{
// Hotel types
if (isset($filterSettings['hotelTypes']) && is_array($filterSettings['hotelTypes']) && count($filterSettings['hotelTypes']) > 0) {
$qb->andWhere($qb->expr()->in(
'date.hotel_type',
$qb->createNamedParameter($filterSettings['hotelTypes'], Connection::PARAM_INT_ARRAY)
));
}
}
protected function addBoardTypesFilterConditions(QueryBuilder $qb, array $filterSettings): void
{
// Board types
if (isset($filterSettings['boardTypes']) && is_array($filterSettings['boardTypes']) && count($filterSettings['boardTypes']) > 0) {
$qb->andWhere($qb->expr()->in(
'date.board_bus_pro_id',
$qb->createNamedParameter($filterSettings['boardTypes'], Connection::PARAM_INT_ARRAY)
));
}
}
protected function addRoomTypesFilterConditions(QueryBuilder $qb, array $filterSettings): void
{
// Room types
if (isset($filterSettings['roomTypes']) && is_array($filterSettings['roomTypes']) && count($filterSettings['roomTypes']) > 0) {
$qb->andWhere($qb->expr()->in(
'room.type',
$qb->createNamedParameter($filterSettings['roomTypes'], Connection::PARAM_INT_ARRAY)
));
}
}
protected function addTransportationFilterConditions(QueryBuilder $qb, array $filterSettings): void
{
// Transportation
if (false === empty($filterSettings['bus'])) {
$qb->andWhere($qb->expr()->eq('date.bus_available', 1));
}
}
}
@@ -0,0 +1,59 @@
<?php
namespace EP\EpProducts\Domain\Repository;
use EP\EpProducts\Domain\Model\AbstractDestination;
/***************************************************************
*
* 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 CityRepository extends AbstractRepository
{
public function getTeasersByCountryOrRegionAndSeason(int $regionUid = 0, int $countryUid = 0, string $season = 'w', int $storagePid = 0)
{
if ($season === null) {
$season = AbstractDestination::SEASON_WINTER;
}
$query = $this->createQuery();
$constraints = [
$query->equals('season', $season),
$query->equals('excludeFromTeasergroups', 0)
];
if (0 < $regionUid) {
$constraints[] = $query->equals('region', $regionUid);
} elseif (0 < $countryUid) {
$constraints[] = $query->equals('country', $countryUid);
}
if (0 < $storagePid) {
$constraints[] = $query->equals('pid', $storagePid);
}
return $query
->matching($query->logicalAnd($constraints))
->execute()
;
}
}
@@ -0,0 +1,31 @@
<?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 ConceptRepository extends AbstractRepository
{}
@@ -0,0 +1,172 @@
<?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 CalendR\Event\EventInterface;
use CalendR\Event\Provider\ProviderInterface;
use Doctrine\DBAL\DBALException;
use EP\EpProducts\Domain\Model\Contingent;
use EP\EpProducts\Domain\Model\Hotel;
use EP\EpProducts\Domain\Model\Product;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ContingentRepository extends AbstractRepository implements ProviderInterface
{
/**
* @return EventInterface[]
*
* @throws DBALException
*/
public function getEvents(\DateTime $begin, ?\DateTime $end = null, array $options = []): array
{
$optionsResolver = new OptionsResolver();
$optionsResolver->setRequired(['hotel']);
$optionsResolver->setAllowedTypes('hotel', Hotel::class);
$resolvedOptions = $optionsResolver->resolve($options);
/** @var Hotel $hotel */
$hotel = $resolvedOptions['hotel'];
$qb = $this->getDbConnection()->createQueryBuilder();
$qb
->select('c.status as status', 'c.date as date', 'c.min_price as minPrice', 'c.pax', 'c.available', 'c.room_code')
->from('tx_epproducts_domain_model_contingent', 'c')
->where('c.hotel = :hotelUid')
->andWhere('c.date >= :dateFrom')
->setParameter('hotelUid', $hotel->getUid())
->setParameter('dateFrom', $begin->format('Y-m-d'))
->orderBy('c.date')
;
if (null !== $end) {
$qb
->andWhere('date <= :dateTo')
->setParameter('dateTo', $end->format('Y-m-d'))
;
}
$result = $qb->execute()->fetchAllAssociative();
$dates = [];
foreach ($result as $row) {
if (!\array_key_exists($row['date'], $dates)) {
$dates[$row['date']] = [
'status' => Contingent::STATUS_OK,
'date' => $row['date'],
'pax' => 0,
'available' => 0,
];
}
if (Contingent::STATUS_OK !== $row['status']) {
$dates[$row['date']]['status'] = $row['status'];
}
if ('BelKal' !== $row['room_code']) {
$dates[$row['date']]['pax'] += $row['pax'];
$dates[$row['date']]['available'] += $row['available'];
}
}
$events = [];
foreach ($dates as $row) {
$row['hotel'] = $hotel;
$events[] = Contingent::fromArray($row);
}
return $events;
}
/**
* @return array
*
* @throws DBALException
*/
public function getAvailableContingents(Hotel $hotel, Product $product)
{
$qb = $this->getDbConnection()->createQueryBuilder();
$qb
->select('c.date as date', 'c.min_nights as minNights')
->addSelectLiteral('SUM(c.available) as total')
->addSelectLiteral('SUM(c.pax) as capacity')
->from('tx_epproducts_domain_model_contingent', 'c')
->innerJoin('c', 'tx_epproducts_domain_model_date', 'd', 'c.date = d.date_start AND c.hotel_code = d.hotel_code')
->where('c.hotel = :hotelUid')
->andWhere('d.product = :productUid')
->andWhere('c.available > 0')
->andWhere('c.min_price > 0')
->setParameters([
'hotelUid' => $hotel->getUid(),
'productUid' => $product->getUid(),
])
->groupBy('c.date')
->orderBy('c.date')
;
return $qb->execute()->fetchAllAssociative();
}
/**
* @return array
*
* @throws DBALException
*/
public function getAvailableRooms(string $dateFrom, string $dateTo, Hotel $hotel, Product $product)
{
$qb = $this->getDbConnection()->createQueryBuilder();
$qb
->select('c.date as date', 'c.room_code as code', 'c.room_label as label', 'c.available as available',
'c.min_price as price', 'c.hotel_bus_pro_id as hotelBusProId', 'c.min_nights as minNights',
'c.additional_night_min_price as additionalNightPrice',
'c.additional_night_min_nights as additionalNightMinNights', 'd.bus_pro_id as busProId',
'd.services_included as servicesIncluded', 'd.services_general as servicesOptional',
'd.skipass_included as skiPassIncluded', 'd.season as season')
->from('tx_epproducts_domain_model_contingent', 'c')
->innerJoin('c', 'tx_epproducts_domain_model_date', 'd', 'c.date = d.date_start AND c.hotel_code = d.hotel_code')
->where('c.hotel = :hotelUid')
->andWhere('d.product = :productUid')
->andWhere('c.date >= :dateFrom')
->andWhere('c.date <= :dateTo')
->andWhere('c.min_price > 0')
->setParameters([
'hotelUid' => $hotel->getUid(),
'productUid' => $product->getUid(),
'dateFrom' => $dateFrom,
'dateTo' => $dateTo,
])
->groupBy('c.room_code')
->orderBy('c.pax')
->addOrderBy('c.min_price')
;
return $qb->execute()->fetchAllAssociative();
}
}
@@ -0,0 +1,31 @@
<?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 CountryRepository extends AbstractRepository
{}
@@ -0,0 +1,45 @@
<?php
namespace EP\EpProducts\Domain\Repository;
use EP\EpProducts\Domain\Model\Product;
use TYPO3\CMS\Core\Database\Connection;
class DateRepository extends AbstractRepository
{
public function findForProductAndDate(Product $product, string $date)
{
$query = $this->createQuery();
return $query
->matching($query->logicalAnd([
$query->equals('product', $product),
$query->equals('dateStart', $date),
]))
->execute()
;
}
/**
* @return string[] serialized pickups of each upcoming date, latest first
*/
public function findPickupsForProductAndHotel(int $productUid, int $hotelUid): array
{
$qb = $this->getDbConnection()->createQueryBuilder();
return $qb
->select('date.pickups')
->from('tx_epproducts_domain_model_date', 'date')
->where(
$qb->expr()->eq('date.product', $qb->createNamedParameter($productUid, Connection::PARAM_INT)),
$qb->expr()->eq('date.hotel', $qb->createNamedParameter($hotelUid, Connection::PARAM_INT)),
$qb->expr()->eq('date.group_travel', $qb->createNamedParameter(0, Connection::PARAM_INT)),
'date.date_start >= NOW()'
)
->orderBy('date.date_start', 'DESC')
->addOrderBy('date.uid', 'DESC')
->execute()
->fetchFirstColumn()
;
}
}
@@ -0,0 +1,62 @@
<?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);
}
}
@@ -0,0 +1,56 @@
<?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();
}
}
@@ -0,0 +1,272 @@
<?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\Hotel;
use Symfony\Component\OptionsResolver\OptionsResolver;
use TYPO3\CMS\Core\Database\Connection;
class HotelRepository extends AbstractRepository
{
/**
* @param int $hotelUid
* @return array
* @throws \Doctrine\DBAL\DBALException
*/
public function getSingleByUid($hotelUid)
{
$qb = $this->getQueryBuilder();
$qb
->andWhere('date.hotel = :hotelUid')
->orderBy('date.min_price')
->setParameter('hotelUid', $hotelUid)
->setMaxResults(1)
;
return $qb->execute()->fetchAssociative();
}
/**
* @param int $hotelUid
* @return array
* @throws \Doctrine\DBAL\DBALException
*/
public function getDateIndependentSingleByUid($hotelUid)
{
$qb = $this->getDbConnection()->createQueryBuilder();
$qb
->select(
'hotel.uid as hotelUid', 'hotel.name as hotelName', 'hotel.teaser as hotelTeaser',
'hotel.category as hotelCategory', 'hotel.detail_page as hotelDetailPage',
'country.code as countryCode', 'country.name as country',
'region.name as region'
)
->from('tx_epproducts_domain_model_hotel', 'hotel')
->leftJoin('hotel', 'tx_epproducts_domain_model_country', 'country', 'hotel.country = country.uid')
->leftJoin('hotel', 'tx_epproducts_domain_model_region', 'region', 'hotel.region = region.uid')
->where('hotel.uid = :hotelUid')
->andWhere('hotel.show_as_teaser = 1')
->setParameter('hotelUid', $hotelUid)
;
return $qb->execute()->fetchAssociative();
}
/**
* @param int $productUid
* @return array
* @throws \Doctrine\DBAL\DBALException
*/
public function getListByProduct($productUid)
{
$qb = $this->getQueryBuilder(false);
$qb
->andWhere('date.product = :productUid')
->setParameter('productUid', $productUid)
;
return $qb->execute()->fetchAllAssociative();
}
/**
* @param array $criteria
* @return array
* @throws \Doctrine\DBAL\DBALException
*/
public function getListByCriteria(array $criteria)
{
$optionsResolver = new OptionsResolver();
$optionsResolver->setDefined(['regionUid', 'countryUid', 'conceptUid', 'productUid', 'category', 'type']);
$resolvedCriteria = $optionsResolver->resolve($criteria);
$qb = $this->getQueryBuilder();
if ($resolvedCriteria['regionUid']) {
$qb
->andWhere('date.region = :regionUid')
->setParameter('regionUid', $resolvedCriteria['regionUid'])
;
}
if ($resolvedCriteria['countryUid']) {
$qb
->andWhere('date.country = :countryUid')
->setParameter('countryUid', $resolvedCriteria['countryUid'])
;
}
if ($resolvedCriteria['conceptUid']) {
$qb
->andWhere('date.concept = :conceptUid')
->setParameter('conceptUid', $resolvedCriteria['conceptUid'])
;
}
if ($resolvedCriteria['productUid']) {
$qb
->andWhere('date.product = :productUid')
->setParameter('productUid', $resolvedCriteria['productUid'])
;
}
if ($resolvedCriteria['category']) {
$qb
->andWhere('date.hotel_category = :category')
->setParameter('category', $resolvedCriteria['category'])
;
}
if ($resolvedCriteria['type']) {
$qb
->andWhere('date.hotel_type = :type')
->setParameter('type', $resolvedCriteria['type'])
;
}
return $qb->execute()->fetchAllAssociative();
}
/**
* @param array $criteria
* @param array $excludedHotelUids
* @return array
* @throws \Doctrine\DBAL\DBALException
*/
public function getDateIndependentListByCriteria(array $criteria, array $excludedHotelUids = [])
{
$optionsResolver = new OptionsResolver();
$optionsResolver->setDefined(['regionUid', 'countryUid', 'conceptUid', 'productUid', 'category', 'type']);
$resolvedCriteria = $optionsResolver->resolve($criteria);
$qb = $this->getDbConnection()->createQueryBuilder();
$qb
->select(
'hotel.uid as hotelUid', 'hotel.name as hotelName', 'hotel.teaser as hotelTeaser',
'hotel.category as hotelCategory', 'hotel.detail_page as hotelDetailPage',
'country.code as countryCode', 'country.name as country',
'region.name as region'
)
->from('tx_epproducts_domain_model_hotel', 'hotel')
->leftJoin('hotel', 'tx_epproducts_domain_model_country', 'country', 'hotel.country = country.uid')
->leftJoin('hotel', 'tx_epproducts_domain_model_region', 'region', 'hotel.region = region.uid')
->where('hotel.show_as_teaser = 1')
->add('orderBy', 'FIELD(hotel.type, ' . Hotel::TYPE_SPORTS_CLUB . ') DESC')
->addOrderBy('hotel.name', 'ASC')
;
if ($excludedHotelUids) {
$qb
->andWhere('hotel.uid NOT IN (:excludedHotelUids)')
->setParameter('excludedHotelUids', $excludedHotelUids, Connection::PARAM_INT_ARRAY)
;
}
if ($resolvedCriteria['productUid']) {
$qb
->innerJoin('hotel', 'tx_epproducts_product_hotel_mm', 'mm', 'hotel.uid = mm.uid_foreign')
->andWhere('mm.uid_local = :product')
->setParameter('product', $resolvedCriteria['productUid'])
;
}
if ($resolvedCriteria['countryUid']) {
$qb
->andWhere('hotel.country = :country')
->setParameter('country', $resolvedCriteria['countryUid'])
;
}
if ($resolvedCriteria['regionUid']) {
$qb
->andWhere('hotel.region = :region')
->setParameter('region', $resolvedCriteria['regionUid'])
;
}
if ($resolvedCriteria['category']) {
$qb
->andWhere('hotel.category = :category')
->setParameter('category', $resolvedCriteria['category'])
;
}
if ($resolvedCriteria['type']) {
$qb
->andWhere('hotel.type = :type')
->setParameter('type', $resolvedCriteria['type'])
;
}
return $qb->execute()->fetchAllAssociative();
}
/**
* @param bool $excludeNonSearchable
* @return \TYPO3\CMS\Core\Database\Query\QueryBuilder
* @throws \Doctrine\DBAL\DBALException
*/
protected function getQueryBuilder($excludeNonSearchable = true)
{
$qb = $this->getDbConnection()->createQueryBuilder();
$qb
->select(
'date.hotel as hotelUid', 'date.hotel_name as hotelName', 'date.hotel_teaser as hotelTeaser',
'date.hotel_category as hotelCategory', 'date.hotel_detail_page as hotelDetailPage',
'date.date_start as dateStart', 'date.date_end as dateEnd', 'date.earlybird as earlybird',
'date.new as new', 'date.low_contingent as lowContingent', 'date.board as board',
'date.product_fact as productFact', 'date.hotel_fact as hotelFact', 'date.region_fact as regionFact',
'date.services_included as servicesIncluded', 'date.min_price as minPrice',
'date.pseudo_price as pseudoPrice', 'date.nights as nights', 'date.available as available',
'date.country as country', 'date.country_code as countryCode', 'date.region as region'
)
->from('tx_epproducts_domain_model_date', 'date')
->leftJoin('date', 'tx_epproducts_product_region_mm', 'mm', 'mm.uid_local = date.product')
->addGroupBy('date.hotel')
->addGroupBy('date.date_start')
->addGroupBy('date.nights')
->add('orderBy', 'FIELD(date.hotel_type, ' . Hotel::TYPE_SPORTS_CLUB . ') DESC')
;
if ($excludeNonSearchable) {
$qb->where('date.product_searchable = 1');
}
return $qb;
}
/**
* @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
*/
public function getMapList()
{
$query = $this->createQuery();
$query->matching(
$query->logicalAnd(
$query->greaterThan('latitude', 0),
$query->greaterThan('longitude', 0)
)
);
return $query->execute();
}
}
@@ -0,0 +1,21 @@
<?php
namespace EP\EpProducts\Domain\Repository;
use TYPO3\CMS\Extbase\Persistence\Repository;
class InfoboxRepository extends Repository
{
public function getDefault()
{
$query = $this->createQuery();
$query->getQuerySettings()->setRespectStoragePage(false);
$result = $query
->matching($query->equals('defaultText', true))
->execute()
;
return $result->getFirst();
}
}
@@ -0,0 +1,31 @@
<?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
{}
@@ -0,0 +1,414 @@
<?php
namespace EP\EpProducts\Domain\Repository;
use EP\EpProducts\Domain\Model\Date;
use EP\EpProducts\Domain\Model\Hotel;
use EP\EpProducts\Domain\Model\Product;
use EP\EpProducts\Domain\Model\Room;
use TYPO3\CMS\Core\Database\Connection;
class ProductRepository extends AbstractRepository
{
public function getWatchlist(array $productUids, array $hotelUids): array
{
$qb = $this->getDbConnection()->createQueryBuilder();
$qb
->select(
'date.concept as conceptUid', 'date.concept_name as conceptName',
'date.concept_code as conceptCode', 'con.popup_text as conceptPopupText',
'date.product as productUid', 'date.product_name as productName',
'date.product_detail_page as productDetailPage', 'date.product_feature as productFeature',
'date.country as countryUid','date.country_name as countryName', 'date.country_code as countryCode',
'date.region as regionUid', 'date.region_name as regionName', 'date.region_feature as regionFeature',
'date.date_start as dateStart', 'date.date_end as dateEnd',
'date.hotel as hotelUid', 'date.hotel_name as hotelName', 'date.hotel_category as hotelCategory',
'date.earlybird as earlybird', 'date.new as new', 'date.low_contingent as lowContingent',
'date.board as board', 'date.product_fact as productFact', 'date.hotel_fact as hotelFact',
'date.region_fact as regionFact', 'date.services_included as servicesIncluded',
'date.skipass_included as skiPassIncluded', 'date.min_price as minPrice', 'date.nights as nights',
'date.available as available', 'date.pseudo_price as pseudoPrice'
)
->from('tx_epproducts_domain_model_date', 'date')
->leftJoin('date', 'tx_epproducts_domain_model_concept', 'con', 'date.concept = con.uid')
->where($qb->expr()->in(
'date.product',
$qb->createNamedParameter($productUids, Connection::PARAM_INT_ARRAY))
)
->andWhere($qb->expr()->in(
'date.hotel',
$qb->createNamedParameter($hotelUids, Connection::PARAM_INT_ARRAY))
)
->andWhere($qb->expr()->eq('date.product_searchable', 1))
->orderBy('date.concept_sorting')
->addOrderBy('date.product_name')
->addOrderBy('date.min_price')
->addOrderBy('date.date_start')
->addOrderBy('date.hotel_name')
;
return $qb
->execute()
->fetchAllAssociative()
;
}
public function getSearchResult(array $filterSettings, array $excludedConceptUids = []): array
{
$qb = $this->getDbConnection()->createQueryBuilder();
$qb
->select(
'date.concept as conceptUid', 'date.concept_name as conceptName',
'date.concept_code as conceptCode', 'date.concept_sorting as conceptSorting',
'con.popup_text as conceptPopupText',
'date.product as productUid', 'date.product_name as productName',
'date.product_detail_page as productDetailPage', 'date.product_feature as productFeature',
'date.daytrip as daytrip', 'date.country as countryUid','date.country_name as countryName',
'date.country_code as countryCode', 'date.region as regionUid', 'date.region_name as regionName',
'date.region_feature as regionFeature', 'date.date_start as dateStart', 'date.date_end as dateEnd',
'date.hotel as hotelUid', 'date.hotel_name as hotelName', 'date.hotel_category as hotelCategory',
'date.hotel_type as hotelType', 'date.season as season',
'date.earlybird as earlybird', 'date.new as new', 'date.low_contingent as lowContingent',
'date.board as board', 'date.board_bus_pro_id as boardUid',
'date.product_fact as productFact', 'date.hotel_fact as hotelFact', 'date.region_fact as regionFact',
'date.services_included as servicesIncluded', 'date.skipass_included as skiPassIncluded',
'date.bus_available as busAvailable', 'date.new as new',
'date.min_price as minPrice', 'date.nights as nights', 'date.available as available',
'date.pseudo_price as pseudoPrice', 'date.hide_booking_button as hideBookingButton'
)
// The GROUP BY below collapses many room rows per group; an arbitrary
// room.type would hide most types from the filter facet.
->addSelectLiteral('GROUP_CONCAT(DISTINCT room.type) as roomTypes')
->from('tx_epproducts_domain_model_date', 'date')
->leftJoin('date', 'tx_epproducts_domain_model_concept', 'con', 'date.concept = con.uid')
->leftJoin('date', 'tx_epproducts_domain_model_room', 'room', 'room.date = date.uid')
->where($qb->expr()->andX(
$qb->expr()->eq('date.product_searchable', 1),
$qb->expr()->gt('date.available', 0),
'date.date_start >= NOW()'
))
->groupBy('date.product')
->addGroupBy('date.hotel')
->addGroupBy('date.date_start')
->addGroupBy('date.nights')
->orderBy('date.concept_sorting')
->addOrderBy('important', 'DESC')
->addOrderBy('date.product_name')
->addOrderBy('date.min_price')
->addOrderBy('date.date_start')
->addOrderBy('date.hotel_name')
;
if (count($excludedConceptUids) > 0) {
$qb->andWhere($qb->expr()->notIn(
'date.concept',
$qb->createNamedParameter($excludedConceptUids, Connection::PARAM_INT_ARRAY))
);
}
if ($filterSettings['productsPid']) {
$productsPid = $filterSettings['productsPid'];
$qb->andWhere($qb->expr()->in(
'date.product_pid',
$qb->createNamedParameter($productsPid, Connection::PARAM_INT_ARRAY))
);
}
$this->addFiltersettingsConditions($qb, $filterSettings);
return $qb
->execute()
->fetchAllAssociative()
;
}
public function getTeasers(array $filterSettings, array $excludedConceptUids = [], int $limit = 0): array
{
$qb = $this->getDbConnection()->createQueryBuilder();
$qb
->select(
'date.product as productUid', 'date.product_name as productName',
'date.product_detail_page as productDetailPage', 'date.product_feature as productFeature',
'date.product_teaser as productTeaser', 'date.product_fact as productFact',
'date.product_slug as productSlug',
'date.hotel as hotelUid', 'date.hotel_fact as hotelFact', 'date.hotel_name as hotelName',
'date.hotel_category as hotelCategory', 'date.region_fact as regionFact',
'date.region_name as regionName', 'date.region_feature as regionFeature',
'date.country_name as countryName', 'date.country_code as countryCode',
'date.date_start as dateStart', 'date.date_end as dateEnd', 'date.uid as dateUid',
'date.min_price as minPrice', 'date.pseudo_price as pseudoPrice',
'date.nights as nights', 'date.available as available', 'date.season as season',
'date.skipass_included as skiPassIncluded', 'date.bus_included as busIncluded',
'date.earlybird', 'date.new', 'date.daytrip', 'date.hide_booking_button as hideBookingButton',
'date.low_contingent as lowContingent', 'date.concept as conceptUid',
'date.concept_code as conceptCode', 'date.concept_name as conceptName',
'con.popup_text as conceptPopupText', 'date.board'
)
->from('tx_epproducts_domain_model_date', 'date')
->leftJoin('date', 'tx_epproducts_domain_model_concept', 'con', 'date.concept = con.uid')
->where('date.date_start >= NOW()')
->groupBy('date.product')
->addGroupBy('date.hotel')
->addGroupBy('date.date_start')
->addGroupBy('date.nights')
->having('date.available > 0')
->orderBy('date.important', 'DESC')
->addOrderBy('date.new', 'DESC')
->addOrderBy('date.concept_sorting')
->addOrderBy('date.date_start')
;
if ($filterSettings['productsPid']) {
$productsPid = (array) $filterSettings['productsPid'];
$qb->andWhere($qb->expr()->in(
'date.product_pid',
$qb->createNamedParameter($productsPid, Connection::PARAM_INT_ARRAY))
);
}
if ($limit > 0) {
$qb->setMaxResults($limit);
}
if (empty($filterSettings['productUid'])) {
$qb->andWhere($qb->expr()->eq('date.product_searchable', 1));
} else {
$qb->andWhere($qb->expr()->eq(
'date.product',
$qb->createNamedParameter($filterSettings['productUid'], Connection::PARAM_INT))
);
}
$this->addDateFilterConditions($qb, $filterSettings);
$this->addHotelFilterConditions($qb, $filterSettings);
$this->addCountryRegionAndCityFilterConditions($qb, $filterSettings);
$this->addConceptFilterConditions($qb, $filterSettings);
$this->addTransportationFilterConditions($qb, $filterSettings);
if (count($excludedConceptUids) > 0) {
$qb->andWhere($qb->expr()->notIn(
'concept',
$qb->createNamedParameter($excludedConceptUids, Connection::PARAM_INT_ARRAY))
);
}
return $qb
->execute()
->fetchAllAssociative()
;
}
public function getPricetable(Product $product, Hotel $hotel, array $filterSettings, Date $date = null): array
{
$qb = $this->getDbConnection()->createQueryBuilder();
$qb
->select(
'date.uid as dateUid', 'date.date_start as dateStart', 'date.date_end as dateEnd',
'date.bus_pro_id as dateBusProId', 'date.hotel as hotelUid', 'date.hotel_bus_pro_id as hotelBusProId',
'date.bus_included as dateBusIncluded', 'date.skipass_included as dateSkiPassIncluded',
'date.group_travel as dateGroupTravel',
'date.season as season', 'date.product_detail_page as productDetailPage',
'room.uid as roomUid', 'room.bus_pro_id as roomBusProId', 'room.name as roomName',
'room.price as roomPrice', 'date.discount as roomDiscount', 'date.bus_price as busPrice',
'room.services as roomOptionalServices', 'room.nights as roomNights', 'room.available as roomAvailable',
'room.status as roomStatus'
)
->from('tx_epproducts_domain_model_date', 'date')
->innerJoin('date', 'tx_epproducts_domain_model_room', 'room', 'date.uid = room.date')
->orderBy('room.pax', 'ASC')
->addOrderBy('room.price', 'ASC')
->addOrderBy('room.available', 'DESC')
;
$qb
->where('date.date_start >= NOW()')
->andWhere($qb->expr()->eq(
'date.product',
$qb->createNamedParameter($product->getUid(), Connection::PARAM_INT))
)
->andWhere($qb->expr()->eq(
'date.hotel',
$qb->createNamedParameter($hotel->getUid(), Connection::PARAM_INT))
)
->andWhere($qb->expr()->neq(
'room.status',
$qb->createNamedParameter(Room::ROOM_STATUS_FULLY_BOOKED, Connection::PARAM_INT))
)
;
if ($filterSettings['productsPid']) {
$productsPid = (array) $filterSettings['productsPid'];
$qb->andWhere($qb->expr()->in(
'date.product_pid',
$qb->createNamedParameter($productsPid, Connection::PARAM_INT_ARRAY))
);
}
if ($date !== null) {
$qb->andWhere($qb->expr()->eq(
'date.uid',
$qb->createNamedParameter($date->getUid(), Connection::PARAM_INT))
);
}
$this->addFiltersettingsConditions($qb, $filterSettings);
return $qb
->execute()
->fetchAllAssociative()
;
}
public function getAvailableDates(Product $product, Hotel $hotel, array $filterSettings): array
{
$qb = $this->getDbConnection()->createQueryBuilder();
$qb
->select(
'date.uid as dateUid', 'date.date_start as dateStart', 'date.date_end as dateEnd',
'date.season as season', 'date.min_price as dateMinPrice', 'date.pseudo_price as datePseudoPrice',
'date.discount as dateDiscount', 'date.bus_price as busPrice', 'date.nights as dateNights',
'date.bus_included as dateBusIncluded', 'date.services_included as dateServicesIncluded',
'date.services_general as dateServicesGeneral', 'date.skipass_included as dateSkiPassIncluded',
'date.group_travel as dateGroupTravel',
'date.bus_pro_id as dateBusProId', 'date.hotel_bus_pro_id as hotelBusProId',
'date.available as available', 'date.product_detail_page as productDetailPage',
)
->from('tx_epproducts_domain_model_date', 'date')
->innerJoin('date', 'tx_epproducts_domain_model_room', 'room', 'room.date = date.uid')
->orderBy('date.date_start', 'ASC')
->addOrderBy('date.min_price', 'ASC')
->where('date.date_start >= NOW()')
->andWhere($qb->expr()->eq(
'date.product',
$qb->createNamedParameter($product->getUid(), Connection::PARAM_INT))
)
->andWhere($qb->expr()->eq(
'date.hotel',
$qb->createNamedParameter($hotel->getUid(), Connection::PARAM_INT))
)
->andWhere($qb->expr()->neq(
'room.status',
$qb->createNamedParameter(Room::ROOM_STATUS_FULLY_BOOKED, Connection::PARAM_INT))
)
->groupBy('date.date_start')
;
if ($filterSettings['productsPid']) {
$productsPid = (array) $filterSettings['productsPid'];
$qb->andWhere($qb->expr()->in(
'date.product_pid',
$qb->createNamedParameter($productsPid, Connection::PARAM_INT_ARRAY))
);
}
$this->addFiltersettingsConditions($qb, $filterSettings, true);
return $qb
->execute()
->fetchAllAssociative()
;
}
public function hasDates(Product $product): bool
{
$qb = $this->getDbConnection()->createQueryBuilder();
$result = $qb
->select('date.uid')
->from('tx_epproducts_domain_model_date', 'date')
->where($qb->expr()->eq(
'date.product',
$qb->createNamedParameter($product->getUid(), Connection::PARAM_INT))
)
->setMaxResults(1)
->execute()
->fetchOne()
;
return $result !== false;
}
public function getDatesForExport(Product $product, Hotel $hotel): array
{
$qb = $this->getDbConnection()->createQueryBuilder();
$qb
->select(
'date.bus_pro_id as dateBusProId', 'date.date_start as dateStart', 'date.date_end as dateEnd',
'date.min_price as dateMinPrice', 'date.discount as dateDiscount', 'date.bus_price as busPrice',
'date.nights as dateNights', 'date.bus_included as dateBusIncluded', 'date.bus_price as busPrice',
'date.services_included as dateServicesIncluded', 'date.services_general as dateServicesGeneral',
'date.skipass_included as dateSkiPassIncluded', 'date.bus_pro_id as dateBusProId',
'date.discount as roomDiscount', 'date.hotel_bus_pro_id as hotelBusProId', 'date.pickups as pickups',
'room.uid as roomUid', 'room.bus_pro_id as roomBusProId', 'room.code as roomCode',
'room.name as roomName', 'room.price as roomPrice', 'room.pax as roomPax',
'room.services as roomOptionalServices', 'room.nights as roomNights', 'room.available as roomAvailable'
)
->from('tx_epproducts_domain_model_date', 'date')
->innerJoin('date', 'tx_epproducts_domain_model_room', 'room', 'room.date = date.uid')
->orderBy('date.date_start', 'ASC')
->addOrderBy('date.min_price', 'ASC')
->where('date.date_start >= NOW()')
->andWhere($qb->expr()->eq(
'date.product',
$qb->createNamedParameter($product->getUid(), Connection::PARAM_INT))
)
->andWhere($qb->expr()->eq(
'date.hotel',
$qb->createNamedParameter($hotel->getUid(), Connection::PARAM_INT))
)
->andWhere($qb->expr()->neq(
'room.status',
$qb->createNamedParameter(Room::ROOM_STATUS_FULLY_BOOKED, Connection::PARAM_INT))
)
;
return $qb
->execute()
->fetchAllAssociative()
;
}
public function getEventPriceTable(Product $product): array
{
$qb = $this->getDbConnection()->createQueryBuilder();
$qb
->select(
'date.bus_pro_id as dateBusProId', 'date.hotel_bus_pro_id as hotelBusProId',
'date.date_end as dateEnd', 'date.hotel as hotelUid', 'date.hotel_name as hotelName',
'date.hotel_header_title as hotelTitle', 'date.hotel_category as hotelCategory',
'room.name as roomName', 'room.pax as roomPax', 'room.price as roomPrice',
'room.available as available',
'hotel.detail_page as hotelDetailPageUid', 'hotel.short_name as hotelShortName',
'hotel.show_as_teaser as hotelShowAsTeaser',
'hotel_mapping.detail_page as hotelMappingDetailPageUid',
)
->from('tx_epproducts_domain_model_date', 'date')
->innerJoin('date', 'tx_epproducts_domain_model_room', 'room', 'room.date = date.uid')
->innerJoin('date', 'tx_epproducts_domain_model_hotel', 'hotel', 'hotel.uid = date.hotel')
->leftJoin('hotel', 'tx_epproducts_domain_model_hotel_mapping', 'hotel_mapping', 'hotel_mapping.product = date.product AND hotel_mapping.hotel = date.hotel')
->where($qb->expr()->eq(
'date.product',
$qb->createNamedParameter($product->getUid(), Connection::PARAM_INT))
)
->andWhere($qb->expr()->neq(
'room.status',
$qb->createNamedParameter(Room::ROOM_STATUS_FULLY_BOOKED, Connection::PARAM_INT))
)
->orderBy('room.available', 'DESC')
->addOrderBy('room.name', 'ASC')
;
return $qb
->execute()
->fetchAllAssociative()
;
}
}
@@ -0,0 +1,56 @@
<?php
namespace EP\EpProducts\Domain\Repository;
use EP\EpProducts\Domain\Model\AbstractDestination;
/***************************************************************
*
* 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 RegionRepository extends AbstractRepository
{
public function getTeasersByCountryAndSeason(int $countryUid, string $season = 'w', int $storagePid = 0)
{
if ($season === null) {
$season = AbstractDestination::SEASON_WINTER;
}
$query = $this->createQuery();
$constraints = [
$query->equals('country', $countryUid),
$query->equals('season', $season),
$query->equals('excludeFromTeasergroups', 0)
];
if (0 < $storagePid) {
$constraints[] = $query->equals('pid', $storagePid);
}
return $query
->matching($query->logicalAnd($constraints))
->execute()
;
}
}
@@ -0,0 +1,31 @@
<?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
{}
@@ -0,0 +1,31 @@
<?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
{}
@@ -0,0 +1,71 @@
<?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();
}
}
@@ -0,0 +1,52 @@
<?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();
}
}
@@ -0,0 +1,6 @@
<?php
namespace EP\EpProducts\Domain\Repository;
class TravelinfoRepository extends AbstractRepository
{}
@@ -0,0 +1,31 @@
<?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
{}
@@ -0,0 +1,57 @@
<?php
namespace EP\EpProducts\Domain\Serialization;
/***************************************************************
*
* Copyright notice
*
* (c) 2018 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use EP\EpProducts\Domain\Model\Fact;
use EP\EpProducts\Utility\SerializationUtility;
class City
{
/**
* @param \EP\EpProducts\Domain\Model\City $entity
* @return array
*/
public static function fromEntity(\EP\EpProducts\Domain\Model\City $entity)
{
$city = [];
$city['@id'] = $entity->getUid();
$city['name'] = $entity->getName();
$city['description'] = SerializationUtility::sanitizeText($entity->getDescription());
$city['party'] = SerializationUtility::sanitizeText($entity->getParty());
$city['leisure'] = SerializationUtility::sanitizeText($entity->getLeisure());
$city['facts'] = [];
$city['facts']['fact'] = array_map(function ($fact) {
/** @var Fact $fact */
return htmlspecialchars($fact->getName());
}, $entity->getFacts()->toArray());
return $city;
}
}
@@ -0,0 +1,63 @@
<?php
namespace EP\EpProducts\Domain\Serialization;
/***************************************************************
*
* 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 Date
{
/**
* @param array $array
* @return array
*/
public static function fromArray(array $array)
{
$date = [
'servicesincluded' => [],
'servicesoptional' => [],
'rooms' => [],
];
$date['@id'] = $array['dateBusProId'];
$date['from'] = $array['dateStart'];
$date['to'] = $array['dateEnd'];
$date['minprice'] = (float) $array['dateMinPrice'];
$date['nights'] = $array['dateNights'];
$date['skipassincluded'] = $array['dateSkiPassIncluded'];
$date['busincluded'] = $array['dateBusIncluded'];
$date['servicesincluded']['service'] = unserialize($array['dateServicesIncluded']);
$servicesGeneral = unserialize($array['dateServicesGeneral']);
$date['servicesoptional'] = Services::fromArray($servicesGeneral);
$date['pickups'] = [];
foreach (unserialize($array['pickups']) as $row)
{
$date['pickups']['pickup'][] = $row;
}
return $date;
}
}
@@ -0,0 +1,56 @@
<?php
namespace EP\EpProducts\Domain\Serialization;
use EP\EpProducts\Utility\SerializationUtility;
/***************************************************************
*
* 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 Hotel
{
/**
* @param \EP\EpProducts\Domain\Model\Hotel $entity
* @return array
*/
public static function fromEntity(\EP\EpProducts\Domain\Model\Hotel $entity)
{
$hotel = [
'dates' => [],
'images' => [],
];
$hotel['@id'] = $entity->getUid();
$hotel['@code'] = $entity->getCode();
$hotel['name'] = $entity->getName();
$hotel['category'] = \EP\EpProducts\Domain\Model\Hotel::$categoryLabels[$entity->getCategory()];
$hotel['type'] = \EP\EpProducts\Domain\Model\Hotel::$typeLabels[$entity->getType()];
$hotel['description'] = SerializationUtility::sanitizeText($entity->getDescription());
$hotel['roomtypes'] = SerializationUtility::sanitizeText($entity->getRoomTypes());
$hotel['features'] = SerializationUtility::sanitizeText($entity->getFeatures());
$hotel['images']['image'] = SerializationUtility::preprocessImages($entity->getResellerImages());
return $hotel;
}
}
Loaded 100 of 778 files, more files were not shown because too many files have changed in this diff. Show more