BREAKING: TYPO3 v12 support (#44)

* Migrated all fixtures to PHP.
* Removed version specific adjustments.
This commit is contained in:
Daniel Siepmann 2023-11-27 10:04:42 +01:00 committed by GitHub
parent a9f3f108e3
commit 81065f5c67
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
208 changed files with 4394 additions and 3438 deletions

1
.gitattributes vendored
View file

@ -1,4 +1,5 @@
Tests export-ignore
Patches export-ignore
.gitlab-ci.yml export-ignore
shell.nix export-ignore

View file

@ -15,12 +15,9 @@ jobs:
strategy:
matrix:
php-version:
- 7.2
- 7.3
- 7.4
- 8.0
- 8.1
- 8.2
- 8.3
steps:
- name: Checkout
uses: actions/checkout@v3
@ -43,7 +40,7 @@ jobs:
- name: Install PHP
uses: shivammathur/setup-php@v2
with:
php-version: "7.4"
php-version: "8.2"
tools: composer:v2
- name: Install xmllint
@ -71,14 +68,14 @@ jobs:
- name: Install PHP
uses: shivammathur/setup-php@v2
with:
php-version: "8.1"
php-version: "8.2"
tools: composer:v2
- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-suggest
- name: Coding Guideline
run: ./vendor/bin/php-cs-fixer fix
run: ./vendor/bin/php-cs-fixer fix --dry-run --diff
code-quality:
runs-on: ubuntu-latest
@ -87,20 +84,12 @@ jobs:
strategy:
matrix:
include:
- php-version: '7.2'
typo3-version: '^10.4'
- php-version: '7.3'
typo3-version: '^10.4'
- php-version: '7.4'
typo3-version: '^10.4'
- php-version: '7.4'
typo3-version: '^11.5'
- php-version: '8.0'
typo3-version: '^11.5'
- php-version: '8.1'
typo3-version: '^11.5'
typo3-version: '^12.4'
- php-version: '8.2'
typo3-version: '^11.5'
typo3-version: '^12.4'
- php-version: '8.3'
typo3-version: '^12.4'
steps:
- uses: actions/checkout@v3
@ -124,20 +113,12 @@ jobs:
strategy:
matrix:
include:
- php-version: '7.2'
typo3-version: '^10.4'
- php-version: '7.3'
typo3-version: '^10.4'
- php-version: '7.4'
typo3-version: '^10.4'
- php-version: '7.4'
typo3-version: '^11.5'
- php-version: '8.0'
typo3-version: '^11.5'
- php-version: '8.1'
typo3-version: '^11.5'
typo3-version: '^12.4'
- php-version: '8.2'
typo3-version: '^11.5'
typo3-version: '^12.4'
- php-version: '8.3'
typo3-version: '^12.4'
steps:
- uses: actions/checkout@v3
@ -151,4 +132,4 @@ jobs:
run: composer require --no-interaction --prefer-dist --no-progress "typo3/cms-core:${{ matrix.typo3-version }}" "typo3/cms-extbase:${{ matrix.typo3-version }}" "typo3/cms-frontend:${{ matrix.typo3-version }}" "typo3/cms-fluid:${{ matrix.typo3-version }}" "typo3/cms-filelist:${{ matrix.typo3-version }}" "typo3/cms-backend:${{ matrix.typo3-version }}" "typo3/cms-fluid-styled-content:${{ matrix.typo3-version }}"
- name: PHPUnit Tests
run: ./vendor/bin/phpunit --testdox
run: ./vendor/bin/phpunit --display-incomplete --display-skipped --display-deprecations --display-errors --display-notices --display-warnings

View file

@ -9,20 +9,26 @@ return (new \PhpCsFixer\Config())
->setRules([
'@DoctrineAnnotation' => true,
'@PSR2' => true,
'array_indentation' => true,
'array_syntax' => ['syntax' => 'short'],
'attribute_empty_parentheses' => true,
'blank_line_after_opening_tag' => true,
'braces' => ['allow_single_line_closure' => true],
'cast_spaces' => ['space' => 'none'],
'compact_nullable_typehint' => true,
'concat_space' => ['spacing' => 'one'],
'declare_equal_normalize' => ['space' => 'none'],
'declare_strict_types' => true,
'dir_constant' => true,
'fully_qualified_strict_types' => false,
'function_to_constant' => ['functions' => ['get_called_class', 'get_class', 'get_class_this', 'php_sapi_name', 'phpversion', 'pi']],
'function_typehint_space' => true,
'global_namespace_import' => ['import_classes' => true, 'import_constants' => true, 'import_functions' => true],
'lowercase_cast' => true,
'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'],
'modernize_strpos' => true,
'modernize_types_casting' => true,
'multiline_whitespace_before_semicolons' => ['strategy' => 'new_line_for_chained_calls'],
'native_function_casing' => true,
'new_with_braces' => true,
'no_alias_functions' => true,
@ -32,12 +38,14 @@ return (new \PhpCsFixer\Config())
'no_extra_blank_lines' => true,
'no_leading_import_slash' => true,
'no_leading_namespace_whitespace' => true,
'no_multiline_whitespace_around_double_arrow' => true,
'no_null_property_initialization' => true,
'no_short_bool_cast' => true,
'no_singleline_whitespace_before_semicolons' => true,
'no_superfluous_elseif' => true,
'no_trailing_comma_in_singleline_array' => true,
'no_unneeded_control_parentheses' => true,
'no_unneeded_import_alias' => true,
'no_unused_imports' => true,
'no_useless_else' => true,
'no_whitespace_in_blank_line' => true,
@ -54,8 +62,8 @@ return (new \PhpCsFixer\Config())
'phpdoc_types' => true,
'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'],
'return_type_declaration' => ['space_before' => 'none'],
'single_quote' => true,
'single_line_comment_style' => ['comment_types' => ['hash']],
'single_quote' => true,
'single_trait_insert_per_statement' => true,
'trailing_comma_in_multiline' => ['elements' => ['arrays']],
'whitespace_after_comma_in_array' => true,

View file

@ -1,178 +0,0 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Backports\V12\Pagination;
// Original source: https://github.com/TYPO3/typo3/blob/b60cf59fbe7875aff5ee1ba4c56155301694d6b8/typo3/sysext/core/Classes/Pagination/SlidingWindowPagination.php
// Remove once we have v12 as minimum version.
use TYPO3\CMS\Core\Pagination\PaginationInterface;
use TYPO3\CMS\Core\Pagination\PaginatorInterface;
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
final class SlidingWindowPagination implements PaginationInterface
{
/**
* @var int
*/
protected $displayRangeStart = 0;
/**
* @var int
*/
protected $displayRangeEnd = 0;
/**
* @var bool
*/
protected $hasLessPages = false;
/**
* @var bool
*/
protected $hasMorePages = false;
/**
* @var int
*/
protected $maximumNumberOfLinks = 0;
/**
* @var PaginatorInterface
*/
protected $paginator;
public function __construct(PaginatorInterface $paginator, int $maximumNumberOfLinks = 0)
{
$this->paginator = $paginator;
if ($maximumNumberOfLinks > 0) {
$this->maximumNumberOfLinks = $maximumNumberOfLinks;
}
$this->calculateDisplayRange();
}
public function getPreviousPageNumber(): ?int
{
$previousPage = $this->paginator->getCurrentPageNumber() - 1;
if ($previousPage > $this->paginator->getNumberOfPages()) {
return null;
}
return $previousPage >= $this->getFirstPageNumber() ? $previousPage : null;
}
public function getNextPageNumber(): ?int
{
$nextPage = $this->paginator->getCurrentPageNumber() + 1;
return $nextPage <= $this->paginator->getNumberOfPages() ? $nextPage : null;
}
public function getFirstPageNumber(): int
{
return 1;
}
public function getLastPageNumber(): int
{
return $this->paginator->getNumberOfPages();
}
public function getStartRecordNumber(): int
{
if ($this->paginator->getCurrentPageNumber() > $this->paginator->getNumberOfPages()) {
return 0;
}
return $this->paginator->getKeyOfFirstPaginatedItem() + 1;
}
public function getEndRecordNumber(): int
{
if ($this->paginator->getCurrentPageNumber() > $this->paginator->getNumberOfPages()) {
return 0;
}
return $this->paginator->getKeyOfLastPaginatedItem() + 1;
}
public function getAllPageNumbers(): array
{
return range($this->displayRangeStart, $this->displayRangeEnd);
}
public function getDisplayRangeStart(): int
{
return $this->displayRangeStart;
}
public function getDisplayRangeEnd(): int
{
return $this->displayRangeEnd;
}
public function getHasLessPages(): bool
{
return $this->hasLessPages;
}
public function getHasMorePages(): bool
{
return $this->hasMorePages;
}
public function getMaximumNumberOfLinks(): int
{
return $this->maximumNumberOfLinks;
}
public function getPaginator(): PaginatorInterface
{
return $this->paginator;
}
protected function calculateDisplayRange(): void
{
$maximumNumberOfLinks = $this->maximumNumberOfLinks;
$numberOfPages = $this->paginator->getNumberOfPages();
if ($maximumNumberOfLinks > $numberOfPages) {
$maximumNumberOfLinks = $numberOfPages;
}
$currentPage = $this->paginator->getCurrentPageNumber();
$delta = floor($maximumNumberOfLinks / 2);
$this->displayRangeStart = (int)($currentPage - $delta);
$this->displayRangeEnd = (int)($currentPage + $delta - ($maximumNumberOfLinks % 2 === 0 ? 1 : 0));
if ($this->displayRangeStart < 1) {
$this->displayRangeEnd -= $this->displayRangeStart - 1;
}
if ($this->displayRangeEnd > $numberOfPages) {
$this->displayRangeStart -= $this->displayRangeEnd - $numberOfPages;
}
$this->displayRangeStart = (int)max($this->displayRangeStart, 1);
$this->displayRangeEnd = (int)min($this->displayRangeEnd, $numberOfPages);
$this->hasLessPages = $this->displayRangeStart > 2;
$this->hasMorePages = $this->displayRangeEnd + 1 < $this->paginator->getNumberOfPages();
}
}

View file

@ -28,15 +28,7 @@ use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
class CacheManager
{
/**
* @var Typo3CacheManager
*/
private $cacheManager;
/**
* @var array
*/
private $tags = [
private array $tags = [
'tx_events_domain_model_date',
'tx_events_domain_model_event',
'tx_events_domain_model_organizer',
@ -45,9 +37,8 @@ class CacheManager
];
public function __construct(
Typo3CacheManager $cacheManager
private readonly Typo3CacheManager $cacheManager
) {
$this->cacheManager = $cacheManager;
}
public function addAllCacheTagsToPage(ContentObjectRenderer $cObject): void

View file

@ -30,6 +30,7 @@ use TYPO3\CMS\Core\Cache\CacheManager;
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Frontend\Event\ModifyCacheLifetimeForPageEvent;
use WerkraumMedia\Events\Domain\Model\Date;
use WerkraumMedia\Events\Events\Controller\DateListVariables;
@ -41,40 +42,30 @@ use WerkraumMedia\Events\Events\Controller\DateListVariables;
*/
class PageCacheTimeout implements SingletonInterface
{
/**
* @var DateTimeImmutable|null
*/
private $timeout;
private ?DateTimeImmutable $timeout = null;
/**
* @var FrontendInterface
*/
private $runtimeCache;
/**
* @var Context
*/
private $context;
private FrontendInterface $runtimeCache;
public function __construct(
CacheManager $cacheManager,
Context $context
private readonly Context $context
) {
$this->runtimeCache = $cacheManager->getCache('runtime');
$this->context = $context;
}
public function calculateCacheTimout(
array $parameters
): int {
$typo3Timeout = $parameters['cacheTimeout'];
public function modifyCacheLifetimeForPage(ModifyCacheLifetimeForPageEvent $event): void
{
$ourTimeout = $this->getTimeout();
if ($ourTimeout === null) {
return $typo3Timeout;
return;
}
return min($typo3Timeout, $ourTimeout);
$event->setCacheLifetime(
min(
$event->getCacheLifetime(),
$ourTimeout
)
);
}
public function trackDates(DateListVariables $event): void
@ -85,14 +76,10 @@ class PageCacheTimeout implements SingletonInterface
}
if ($event->getDemand()->shouldShowUpcoming()) {
$this->trackTimeoutByDate($event, static function (Date $date) {
return $date->getStart();
});
$this->trackTimeoutByDate($event, static fn (Date $date) => $date->getStart());
}
$this->trackTimeoutByDate($event, static function (Date $date) {
return $date->getEnd();
});
$this->trackTimeoutByDate($event, static fn (Date $date) => $date->getEnd());
}
/**
@ -126,7 +113,8 @@ class PageCacheTimeout implements SingletonInterface
return;
}
$this->runtimeCache->remove('core-tslib_fe-get_cache_timeout');
$id = $GLOBALS['TYPO3_REQUEST']->getAttribute('routing')->getPageId();
$this->runtimeCache->remove('cacheLifeTimeForPage_' . $id);
$this->timeout = $newTimeout;
}
@ -149,9 +137,4 @@ class PageCacheTimeout implements SingletonInterface
return $execution;
}
public static function register(): void
{
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['get_cache_timeout']['events'] = self::class . '->calculateCacheTimout';
}
}

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Command;
use Symfony\Component\Console\Command\Command;
@ -11,23 +13,11 @@ use WerkraumMedia\Events\Service\DestinationDataImportService;
class ImportDestinationDataViaAllConfigruationsCommand extends Command
{
/**
* @var DestinationDataImportService
*/
private $destinationDataImportService;
/**
* @var ImportFactory
*/
private $importFactory;
public function __construct(
DestinationDataImportService $destinationDataImportService,
ImportFactory $importFactory
private readonly DestinationDataImportService $destinationDataImportService,
private readonly ImportFactory $importFactory
) {
parent::__construct();
$this->destinationDataImportService = $destinationDataImportService;
$this->importFactory = $importFactory;
}
public function configure(): void

View file

@ -1,7 +1,10 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Command;
use Exception;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
@ -12,23 +15,11 @@ use WerkraumMedia\Events\Service\DestinationDataImportService;
class ImportDestinationDataViaConfigruationCommand extends Command
{
/**
* @var DestinationDataImportService
*/
private $destinationDataImportService;
/**
* @var ImportFactory
*/
private $importFactory;
public function __construct(
DestinationDataImportService $destinationDataImportService,
ImportFactory $importFactory
private readonly DestinationDataImportService $destinationDataImportService,
private readonly ImportFactory $importFactory
) {
parent::__construct();
$this->destinationDataImportService = $destinationDataImportService;
$this->importFactory = $importFactory;
}
public function configure(): void
@ -51,7 +42,7 @@ class ImportDestinationDataViaConfigruationCommand extends Command
if (is_numeric($configurationUid)) {
$configurationUid = (int)$configurationUid;
} else {
throw new \Exception('No numeric uid for configuration provided.', 1643267138);
throw new Exception('No numeric uid for configuration provided.', 1643267138);
}
$import = $this->importFactory->createFromUid(

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Command;
use Symfony\Component\Console\Command\Command;
@ -10,16 +12,9 @@ use WerkraumMedia\Events\Service\CleanupService;
class RemoveAllCommand extends Command
{
/**
* @var CleanupService
*/
private $cleanupService;
public function __construct(
CleanupService $cleanupService
private readonly CleanupService $cleanupService
) {
$this->cleanupService = $cleanupService;
parent::__construct();
}

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Command;
use Symfony\Component\Console\Command\Command;
@ -10,16 +12,9 @@ use WerkraumMedia\Events\Service\CleanupService;
class RemovePastCommand extends Command
{
/**
* @var CleanupService
*/
private $cleanupService;
public function __construct(
CleanupService $cleanupService
private readonly CleanupService $cleanupService
) {
$this->cleanupService = $cleanupService;
parent::__construct();
}

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Controller;
/*
@ -21,12 +23,12 @@ namespace WerkraumMedia\Events\Controller;
* 02110-1301, USA.
*/
use TYPO3\CMS\Core\Http\ImmediateResponseException;
use TYPO3\CMS\Core\Http\PropagateResponseException;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
use TYPO3\CMS\Frontend\Controller\ErrorController;
use TYPO3Fluid\Fluid\View\ViewInterface;
use WerkraumMedia\Events\Caching\CacheManager;
class AbstractController extends ActionController
@ -49,7 +51,7 @@ class AbstractController extends ActionController
{
parent::initializeAction();
$cObject = $this->configurationManager->getContentObject();
$cObject = $this->request->getAttribute('currentContentObject');
if ($cObject instanceof ContentObjectRenderer) {
$this->cacheManager->addAllCacheTagsToPage($cObject);
}
@ -58,12 +60,12 @@ class AbstractController extends ActionController
/**
* Extend original to also add data from current cobject if available.
*/
protected function resolveView()
protected function resolveView(): ViewInterface
{
$view = parent::resolveView();
$view->assign('data', []);
$cObject = $this->configurationManager->getContentObject();
$cObject = $this->request->getAttribute('currentContentObject');
if ($cObject instanceof ContentObjectRenderer && is_array($cObject->data)) {
$view->assign('data', $cObject->data);
}
@ -73,17 +75,9 @@ class AbstractController extends ActionController
protected function trigger404(string $message): void
{
$errorController = GeneralUtility::makeInstance(ErrorController::class);
if (class_exists(ImmediateResponseException::class)) {
throw new ImmediateResponseException(
$errorController->pageNotFoundAction($GLOBALS['TYPO3_REQUEST'], $message),
1695881164
);
}
throw new PropagateResponseException(
$errorController->pageNotFoundAction($this->request, $message),
GeneralUtility::makeInstance(ErrorController::class)
->pageNotFoundAction($this->request, $message),
1695881170
);
}

View file

@ -1,9 +1,12 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Controller;
use Exception;
use Psr\Http\Message\ResponseInterface;
use Throwable;
use TYPO3\CMS\Core\EventDispatcher\EventDispatcher;
use TYPO3\CMS\Extbase\Annotation as Extbase;
use TYPO3\CMS\Extbase\Service\ExtensionService;
use WerkraumMedia\Events\Domain\Model\Date;
@ -16,73 +19,24 @@ use WerkraumMedia\Events\Events\Controller\DateSearchVariables;
use WerkraumMedia\Events\Pagination\Factory;
use WerkraumMedia\Events\Service\DataProcessingForModels;
class DateController extends AbstractController
final class DateController extends AbstractController
{
/**
* @var DateDemandFactory
*/
protected $demandFactory;
/**
* @var dateRepository
*/
protected $dateRepository;
/**
* @var regionRepository
*/
protected $regionRepository;
/**
* @var CategoryRepository
*/
protected $categoryRepository;
/**
* @var Factory
*/
protected $paginationFactory;
/**
* @var DataProcessingForModels
*/
protected $dataProcessing;
/**
* @var EventDispatcher
*/
protected $eventDispatcher;
/**
* @var ExtensionService
*/
protected $extensionService;
public function __construct(
DateDemandFactory $demandFactory,
DateRepository $dateRepository,
RegionRepository $regionRepository,
CategoryRepository $categoryRepository,
Factory $paginationFactory,
DataProcessingForModels $dataProcessing,
EventDispatcher $eventDispatcher,
ExtensionService $extensionService
private readonly DateDemandFactory $demandFactory,
private readonly DateRepository $dateRepository,
private readonly RegionRepository $regionRepository,
private readonly CategoryRepository $categoryRepository,
private readonly Factory $paginationFactory,
private readonly DataProcessingForModels $dataProcessing,
private readonly ExtensionService $extensionService
) {
$this->demandFactory = $demandFactory;
$this->dateRepository = $dateRepository;
$this->regionRepository = $regionRepository;
$this->categoryRepository = $categoryRepository;
$this->paginationFactory = $paginationFactory;
$this->dataProcessing = $dataProcessing;
$this->eventDispatcher = $eventDispatcher;
$this->extensionService = $extensionService;
}
protected function initializeAction(): void
{
parent::initializeAction();
$contentObject = $this->configurationManager->getContentObject();
$contentObject = $this->request->getAttribute('currentContentObject');
if ($contentObject !== null) {
$this->demandFactory->setContentObjectRenderer($contentObject);
}
@ -91,14 +45,10 @@ class DateController extends AbstractController
$this->handlePostRequest();
}
/**
* @param array $search
* @param int $currentPage
*/
public function listAction(
array $search = [],
int $currentPage = 1
): void {
): ResponseInterface {
$demand = $this->demandFactory->fromSettings($this->settings);
if ($search !== []) {
$demand = $this->demandFactory->createFromRequestValues($search, $this->settings);
@ -117,15 +67,13 @@ class DateController extends AbstractController
)
));
if (!$event instanceof DateListVariables) {
throw new \Exception('Did not retrieve DateSearchVariables from event dispatcher, got: ' . get_class($event), 1657542318);
throw new Exception('Did not retrieve DateSearchVariables from event dispatcher, got: ' . $event::class, 1657542318);
}
$this->view->assignMultiple($event->getVariablesForView());
return $this->htmlResponse();
}
/**
* @param array $search
*/
public function searchAction(array $search = []): void
public function searchAction(array $search = []): ResponseInterface
{
$demand = $this->demandFactory->fromSettings($this->settings);
if ($search !== []) {
@ -136,33 +84,34 @@ class DateController extends AbstractController
$search,
$demand,
$this->regionRepository->findAll(),
$this->categoryRepository->findAllCurrentlyAssigned($this->settings['uids']['categoriesParent'] ?? 0, 'categories'),
$this->categoryRepository->findAllCurrentlyAssigned($this->settings['uids']['featuresParent'] ?? 0, 'features')
$this->categoryRepository->findAllCurrentlyAssigned((int)($this->settings['uids']['categoriesParent'] ?? 0), 'categories'),
$this->categoryRepository->findAllCurrentlyAssigned((int)($this->settings['uids']['featuresParent'] ?? 0), 'features')
));
if (!$event instanceof DateSearchVariables) {
throw new \Exception('Did not retrieve DateSearchVariables from event dispatcher, got: ' . get_class($event), 1657542318);
throw new Exception('Did not retrieve DateSearchVariables from event dispatcher, got: ' . $event::class, 1657542318);
}
$this->view->assignMultiple($event->getVariablesForView());
return $this->htmlResponse();
}
public function teaserAction(): void
public function teaserAction(): ResponseInterface
{
$dates = $this->dateRepository->findByUids($this->settings['eventUids']);
$this->view->assign('dates', $dates);
return $this->htmlResponse();
}
/**
* @Extbase\IgnoreValidation("date")
*/
public function showAction(Date $date): void
#[Extbase\IgnoreValidation(['value' => 'date'])]
public function showAction(Date $date): ResponseInterface
{
try {
$date->getEvent();
} catch (Throwable $e) {
} catch (Throwable) {
$this->trigger404('No event found for requested date.');
}
$this->view->assign('date', $date);
return $this->htmlResponse();
}
/**
@ -178,7 +127,7 @@ class DateController extends AbstractController
&& is_array($this->request->getArgument('search'))
) {
$namespace = $this->extensionService->getPluginNamespace(null, null);
$this->redirectToUri($this->configurationManager->getContentObject()->typoLink_URL([
$this->redirectToUri($this->request->getAttribute('currentContentObject')->typoLink_URL([
'parameter' => 't3://page?uid=current',
'additionalParams' => '&' . http_build_query([
$namespace => [

View file

@ -1,38 +1,23 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Controller;
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Extbase\Annotation as Extbase;
use WerkraumMedia\Events\Domain\Model\Dto\EventDemandFactory;
use WerkraumMedia\Events\Domain\Model\Event;
use WerkraumMedia\Events\Domain\Repository\EventRepository;
use WerkraumMedia\Events\Service\DataProcessingForModels;
class EventController extends AbstractController
final class EventController extends AbstractController
{
/**
* @var EventRepository
*/
protected $eventRepository;
/**
* @var DataProcessingForModels
*/
protected $dataProcessing;
/**
* @var EventDemandFactory
*/
protected $demandFactory;
public function __construct(
EventRepository $eventRepository,
DataProcessingForModels $dataProcessing,
EventDemandFactory $demandFactory
private readonly EventRepository $eventRepository,
private readonly DataProcessingForModels $dataProcessing,
private readonly EventDemandFactory $demandFactory
) {
$this->eventRepository = $eventRepository;
$this->dataProcessing = $dataProcessing;
$this->demandFactory = $demandFactory;
}
protected function initializeAction(): void
@ -42,35 +27,37 @@ class EventController extends AbstractController
$this->dataProcessing->setConfigurationManager($this->configurationManager);
}
public function listAction(): void
public function listAction(): ResponseInterface
{
$demand = $this->demandFactory->fromSettings($this->settings);
$events = $this->eventRepository->findByDemand($demand);
$this->view->assign('events', $events);
return $this->htmlResponse();
}
/**
* @Extbase\IgnoreValidation("event")
*/
public function showAction(Event $event): void
#[Extbase\IgnoreValidation(['value' => 'event'])]
public function showAction(Event $event): ResponseInterface
{
$this->view->assign('event', $event);
return $this->htmlResponse();
}
/**
* @deprecated Use listAction instead and configure settings properly.
* Use Settings or something else to switch between list and teaser rendering.
*/
public function teaserAction(): void
public function teaserAction(): ResponseInterface
{
$this->view->assignMultiple([
'events' => $this->eventRepository->findByUids($this->settings['eventUids']),
]);
return $this->htmlResponse();
}
public function searchAction(string $search = ''): void
public function searchAction(string $search = ''): ResponseInterface
{
$this->view->assign('search', $search);
$this->view->assign('events', $this->eventRepository->findSearchWord($search));
return $this->htmlResponse();
}
}

View file

@ -1,7 +1,11 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Domain\DestinationData;
use Exception;
use PDO;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Resource\Folder;
use TYPO3\CMS\Core\Resource\ResourceFactory;
@ -9,43 +13,19 @@ use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper;
use TYPO3\CMS\Extbase\Persistence\Generic\Session;
use WerkraumMedia\Events\Domain\Model\Import;
class ImportFactory
final class ImportFactory
{
/**
* @var ConnectionPool
*/
private $connectionPool;
/**
* @var Session
*/
private $extbasePersistenceSession;
/**
* @var DataMapper
*/
private $dataMapper;
/**
* @var ResourceFactory
*/
private $resourceFactory;
/**
* @var Folder
*/
private $folderInstance;
public function __construct(
ConnectionPool $connectionPool,
Session $extbasePersistenceSession,
DataMapper $dataMapper,
ResourceFactory $resourceFactory
private readonly ConnectionPool $connectionPool,
private readonly Session $extbasePersistenceSession,
private readonly DataMapper $dataMapper,
private readonly ResourceFactory $resourceFactory
) {
$this->connectionPool = $connectionPool;
$this->extbasePersistenceSession = $extbasePersistenceSession;
$this->dataMapper = $dataMapper;
$this->resourceFactory = $resourceFactory;
}
public function createFromUid(int $uid): Import
@ -59,7 +39,7 @@ class ImportFactory
public function createAll(): array
{
return array_map(
[$this, 'create'],
$this->create(...),
$this->fetchImportRecords()
);
}
@ -69,11 +49,11 @@ class ImportFactory
$qb = $this->connectionPool->getQueryBuilderForTable('tx_events_domain_model_import');
$qb->select('*');
$qb->from('tx_events_domain_model_import');
$qb->where($qb->expr()->eq('uid', $qb->createNamedParameter($uid, \PDO::PARAM_INT)));
$qb->where($qb->expr()->eq('uid', $qb->createNamedParameter($uid, PDO::PARAM_INT)));
$result = $qb->execute()->fetch();
$result = $qb->executeQuery()->fetch();
if (is_array($result) === false) {
throw new \Exception('Could not fetch import record with uid "' . $uid . '".', 1643267492);
throw new Exception('Could not fetch import record with uid "' . $uid . '".', 1643267492);
}
$result = array_map('strval', $result);
@ -87,9 +67,9 @@ class ImportFactory
$qb->select('*');
$qb->from('tx_events_domain_model_import');
$result = $qb->execute()->fetchAll();
$result = $qb->executeQuery()->fetchAll();
if (count($result) === 0) {
throw new \Exception('Could not fetch any import record.', 1643267492);
throw new Exception('Could not fetch any import record.', 1643267492);
}
foreach ($result as $key => $entry) {

View file

@ -1,8 +1,10 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Domain\Model;
use TYPO3\CMS\Extbase\Annotation as Extbase;
use TYPO3\CMS\Extbase\Annotation\ORM\Lazy;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
use TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy;
@ -13,41 +15,22 @@ use TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy;
*/
class Category extends AbstractEntity
{
/**
* @var string
*/
protected $title = '';
/**
* @var int
*/
protected $sorting = 0;
/**
* @var bool
*/
protected $hidden = false;
protected int $sorting = 0;
/**
* @var Category|null
*
* @Extbase\ORM\Lazy
*/
#[Lazy]
protected $parent;
/**
* @param Category|null $parent
*/
public function __construct(
$parent,
?Category $parent,
int $pid,
string $title,
bool $hidden
protected string $title,
protected bool $hidden
) {
$this->parent = $parent;
$this->pid = $pid;
$this->title = $title;
$this->hidden = $hidden;
}
public function getTitle(): string
@ -60,10 +43,7 @@ class Category extends AbstractEntity
return $this->sorting;
}
/**
* @return Category|null
*/
public function getParent()
public function getParent(): ?Category
{
if ($this->parent instanceof LazyLoadingProxy) {
$this->parent->_loadRealInstance();

View file

@ -1,7 +1,12 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Domain\Model;
use DateTime;
use DateTimeImmutable;
use DateTimeZone;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
/**
@ -9,60 +14,26 @@ use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
*/
class Date extends AbstractEntity
{
/**
* @var \DateTime
*/
protected $start;
protected DateTime $start;
/**
* @var \DateTime|null
*/
protected $end;
protected ?DateTime $end = null;
/**
* @var string
*/
protected $canceled = 'no';
protected string $canceled = 'no';
/**
* @var Date|null
*/
protected $postponedDate;
protected ?Date $postponedDate = null;
/**
* @var Date|null
*/
protected $originalDate;
protected ?Date $originalDate = null;
/**
* @var \WerkraumMedia\Events\Domain\Model\Event
*/
protected $event;
protected Event $event;
/**
* @var string
*/
protected $canceledLink = '';
protected string $canceledLink = '';
/**
* @var int
*/
protected $_languageUid;
/**
* @return \DateTime $start
*/
public function getStart()
public function getStart(): DateTime
{
return $this->start;
}
/**
* @param \DateTime $start
*
* @return void
*/
public function setStart(\DateTime $start)
public function setStart(DateTime $start): void
{
$this->start = $start;
}
@ -72,20 +43,12 @@ class Date extends AbstractEntity
return $this->getStart()->format('H:i') !== '00:00';
}
/**
* @return \DateTime|null end
*/
public function getEnd()
public function getEnd(): ?DateTime
{
return $this->end;
}
/**
* @param \DateTime|null $end
*
* @return void
*/
public function setEnd($end)
public function setEnd(?DateTime $end): void
{
$this->end = $end;
}
@ -102,55 +65,33 @@ class Date extends AbstractEntity
return $end && $this->getStart()->format('Y-m-d') === $end->format('Y-m-d');
}
/**
* @return Event
*/
public function getEvent(): Event
{
return $this->event;
}
/**
* @param Event $event
*/
public function setEvent(Event $event): self
{
$this->event = $event;
return $this;
}
/**
* @param int $languageUid
*
* @return void
*/
public function setLanguageUid($languageUid)
public function setLanguageUid(int $languageUid): void
{
$this->_languageUid = $languageUid;
}
/**
* @return int
*/
public function getLanguageUid()
public function getLanguageUid(): int
{
return $this->_languageUid;
}
/**
* @return string
*/
public function getCanceled(): string
{
return $this->canceled;
}
/**
* @param string $canceled
*
* @return void
*/
public function setCanceled(string $canceled)
public function setCanceled(string $canceled): void
{
$this->canceled = $canceled;
}
@ -183,22 +124,22 @@ class Date extends AbstractEntity
bool $canceled
): self {
return self::createFromDestinationData(
new \DateTimeImmutable($date['start'], new \DateTimeZone($date['tz'])),
new \DateTimeImmutable($date['end'], new \DateTimeZone($date['tz'])),
new DateTimeImmutable($date['start'], new DateTimeZone($date['tz'])),
new DateTimeImmutable($date['end'], new DateTimeZone($date['tz'])),
$canceled
);
}
public static function createFromDestinationData(
\DateTimeImmutable $start,
\DateTimeImmutable $end,
DateTimeImmutable $start,
DateTimeImmutable $end,
bool $canceled
): self {
$date = new Date();
$date->setLanguageUid(-1);
$date->setStart(new \DateTime($start->format(\DateTime::W3C), $start->getTimezone()));
$date->setEnd(new \DateTime($end->format(\DateTime::W3C), $end->getTimezone()));
$date->setStart(new DateTime($start->format(DateTime::W3C), $start->getTimezone()));
$date->setEnd(new DateTime($end->format(DateTime::W3C), $end->getTimezone()));
if ($canceled) {
$date->setCanceled('canceled');

View file

@ -1,118 +1,79 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Domain\Model\Dto;
use DateTimeImmutable;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class DateDemand
{
/**
* @var string
*/
protected $sortBy = '';
protected string $sortBy = '';
/**
* @var string
*/
protected $sortOrder = '';
protected string $sortOrder = '';
/**
* @var string
*/
protected $categories = '';
protected string $categories = '';
/**
* @var int[]
*/
protected $userCategories = [];
protected array $userCategories = [];
/**
* @var int[]
*/
protected $features = [];
protected array $features = [];
/**
* @var bool
*/
protected $includeSubCategories = false;
protected bool $includeSubCategories = false;
/**
* @var string
*/
protected $categoryCombination = '';
protected string $categoryCombination = '';
/**
* @var int[]
*/
protected $regions = [];
protected array $regions = [];
/**
* @var int[]
*/
protected $locations = [];
protected array $locations = [];
/**
* @var int[]
*/
protected $organizers = [];
protected array $organizers = [];
/**
* @var bool
*/
protected $highlight = false;
protected bool $highlight = false;
/**
* @var string
*/
protected $limit = '';
protected string $limit = '';
/**
* @var \DateTimeImmutable|null
*/
protected $startObject;
protected ?DateTimeImmutable $startObject = null;
/**
* @var \DateTimeImmutable|null
*/
protected $endObject;
protected ?DateTimeImmutable $endObject = null;
/**
* Use midnight as "start".
*
* @var bool
*/
protected $useMidnight = true;
protected bool $useMidnight = true;
/**
* Only show dates that have not started yet.
*
* @var bool
*/
protected $upcoming = false;
protected bool $upcoming = false;
protected string $searchword = '';
/**
* @var string
*/
protected $searchword = '';
/**
* @var array
*
* Synonym1 => ['word1', 'word2', ],
* Synonym2 => ['word3', 'word4', ],
*
*/
protected $synonyms = [];
protected array$synonyms = [];
/**
* @var bool
*/
protected $considerDate = false;
protected bool $considerDate = false;
/**
* @var string
*/
protected $queryCallback = '';
protected string $queryCallback = '';
public function getSortBy(): string
{
@ -165,7 +126,7 @@ class DateDemand
*/
public function setFeatures(array $categories): void
{
$this->features = array_map('intval', $categories);
$this->features = array_map('intval', array_filter($categories));
}
/**
@ -303,7 +264,7 @@ class DateDemand
return $this->synonyms[$searchWord] ?? [];
}
public function getStartObject(): ?\DateTimeImmutable
public function getStartObject(): ?DateTimeImmutable
{
return $this->startObject;
}
@ -327,10 +288,10 @@ class DateDemand
if ($start === null) {
return;
}
$this->startObject = new \DateTimeImmutable(date('Y-m-d H:i', $start));
$this->startObject = new DateTimeImmutable(date('Y-m-d H:i', $start));
}
public function getEndObject(): ?\DateTimeImmutable
public function getEndObject(): ?DateTimeImmutable
{
return $this->endObject;
}
@ -364,7 +325,7 @@ class DateDemand
return;
}
$this->endObject = new \DateTimeImmutable(date('Y-m-d H:i', $end));
$this->endObject = new DateTimeImmutable(date('Y-m-d H:i', $end));
}
public function setUseMidnight(bool $useMidnight): void
@ -387,8 +348,7 @@ class DateDemand
return $this->getStartObject() === null
&& $this->getEndObject() === null
&& $this->useMidnight === false
&& $this->upcoming === false
;
&& $this->upcoming === false;
}
public function shouldShowFromMidnight(): bool

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Domain\Model\Dto;
/*
@ -27,20 +29,11 @@ use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
class DateDemandFactory
{
/**
* @var TypoScriptService
*/
private $typoScriptService;
/**
* @var contentObjectRenderer
*/
private $contentObjectRenderer;
private ?ContentObjectRenderer $contentObjectRenderer = null;
public function __construct(
TypoScriptService $typoScriptService
private readonly TypoScriptService $typoScriptService
) {
$this->typoScriptService = $typoScriptService;
}
public function setContentObjectRenderer(

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Domain\Model\Dto;
class EventDemand

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Domain\Model\Dto;
/*

View file

@ -1,8 +1,11 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Domain\Model;
use TYPO3\CMS\Extbase\Annotation as Extbase;
use TYPO3\CMS\Extbase\Annotation\ORM\Cascade;
use TYPO3\CMS\Extbase\Annotation\ORM\Lazy;
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
@ -10,154 +13,84 @@ use WerkraumMedia\Events\Service\DataProcessingForModels;
class Event extends AbstractEntity
{
/**
* @var string
*/
protected $title = '';
protected string $title = '';
/**
* @var string
*/
protected $subtitle = '';
protected string $subtitle = '';
/**
* @var string
*/
protected $globalId = '';
protected string $globalId = '';
/**
* @var string
*/
protected $slug = '';
protected string $slug = '';
/**
* @var bool
*/
protected $highlight = false;
protected bool $highlight = false;
/**
* @var string
*/
protected $teaser = '';
protected string $teaser = '';
/**
* @var string
*/
protected $details = '';
protected string $details = '';
/**
* @var string
*/
protected $priceInfo = '';
protected string $priceInfo = '';
/**
* @var string
*/
protected $web = '';
protected string $web = '';
/**
* @var string
*/
protected $ticket = '';
protected string $ticket = '';
/**
* @var string
*/
protected $facebook = '';
protected string $facebook = '';
/**
* @var string
*/
protected $youtube = '';
protected string $youtube = '';
/**
* @var string
*/
protected $instagram = '';
protected string $instagram = '';
/**
* @var ObjectStorage<FileReference>
*
* @Extbase\ORM\Cascade remove
*/
protected $images;
#[Cascade(['value' => 'remove'])]
protected ObjectStorage $images;
/**
* @var ObjectStorage<Date>
*
* @Extbase\ORM\Cascade remove
* @Extbase\ORM\Lazy
*/
protected $dates;
#[Cascade(['value' => 'remove'])]
#[Lazy]
protected ObjectStorage $dates;
/**
* @var Location|null
*/
protected $location;
protected ?Location $location = null;
/**
* @var Organizer|null
*/
protected $organizer;
protected ?Organizer $organizer = null;
/**
* @var Region|null
*/
protected $region;
protected ?Region $region = null;
/**
* @var string
*/
protected $pages = '';
protected string $pages = '';
/**
* @var ObjectStorage<Category>
*/
protected $categories;
protected ObjectStorage $categories;
/**
* @var ObjectStorage<Category>
*/
protected $features;
protected ObjectStorage $features;
/**
* @var ObjectStorage<Partner>
*/
protected $partner;
protected ObjectStorage $partner;
/**
* @var ObjectStorage<Event>
*/
protected $referencesEvents;
protected ObjectStorage $referencesEvents;
/**
* @var int
*/
protected $_languageUid;
protected DataProcessingForModels $dataProcessing;
/**
* @var DataProcessingForModels
*/
protected $dataProcessing;
protected string $sourceName = '';
/**
* @var string
*/
protected $sourceName = '';
/**
* @var string
*/
protected $sourceUrl = '';
protected string $sourceUrl = '';
public function __construct()
{
$this->initStorageObjects();
}
/**
* @param DataProcessingForModels $dataProcessing
*/
public function injectDataProcessingForModels(DataProcessingForModels $dataProcessing): void
{
$this->dataProcessing = $dataProcessing;
@ -289,7 +222,7 @@ class Event extends AbstractEntity
}
/**
* @return ObjectStorage<FileReference> $images
* @return ObjectStorage<FileReference>
*/
public function getImages(): ObjectStorage
{
@ -466,9 +399,7 @@ class Event extends AbstractEntity
{
$categories = $categories->toArray();
usort($categories, function (Category $catA, Category $catB) {
return $catA->getSorting() <=> $catB->getSorting();
});
usort($categories, fn (Category $catA, Category $catB) => $catA->getSorting() <=> $catB->getSorting());
return $categories;
}

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Domain\Model;
use TYPO3\CMS\Core\Resource\Folder;
@ -11,83 +13,32 @@ use TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject;
*/
class Import extends AbstractDomainObject
{
/**
* @var int
*/
protected $storagePid;
protected ?int $categoriesPid;
/**
* @var Folder
*/
protected $filesFolder;
/**
* @var int|null
*/
protected $categoriesPid;
/**
* @var Category|null
*/
protected $categoryParent;
/**
* @var int|null
*/
protected $featuresPid;
/**
* @var Category|null
*/
protected $featuresParent;
/**
* @var Region|null
*/
protected $region;
/**
* @var string
*/
protected $restExperience;
/**
* @var string
*/
protected $restSearchQuery;
protected ?int $featuresPid;
public function __construct(
Folder $filesFolder,
int $storagePid,
string $restExperience,
string $restSearchQuery = '',
protected Folder $filesFolder,
protected int $storagePid,
protected string $restExperience,
protected string $restSearchQuery = '',
int $categoriesPid = 0,
?Category $categoryParent = null,
protected ?Category $categoryParent = null,
int $featuresPid = 0,
?Category $featuresParent = null,
?Region $region = null
protected ?Category $featuresParent = null,
protected ?Region $region = null
) {
$this->filesFolder = $filesFolder;
$this->storagePid = $storagePid;
// Do not allow categories on pid 0
if ($categoriesPid === 0) {
$categoriesPid = null;
}
$this->categoriesPid = $categoriesPid;
$this->categoryParent = $categoryParent;
// Do not allow features on pid 0
if ($featuresPid === 0) {
$featuresPid = null;
}
$this->featuresPid = $featuresPid;
$this->featuresParent = $featuresParent;
$this->restExperience = $restExperience;
$this->restSearchQuery = $restSearchQuery;
$this->region = $region;
}
public function getStoragePid(): int

View file

@ -1,80 +1,27 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Domain\Model;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
class Location extends AbstractEntity
{
/**
* @var string
*/
protected $name = '';
/**
* @var string
*/
protected $street = '';
/**
* @var string
*/
protected $zip = '';
/**
* @var string
*/
protected $city = '';
/**
* @var string
*/
protected $district = '';
/**
* @var string
*/
protected $country = '';
/**
* @var string
*/
protected $phone = '';
/**
* @var string
*/
protected $latitude = '';
/**
* @var string
*/
protected $longitude = '';
/**
* @var string
*/
protected $globalId = '';
protected string $globalId = '';
public function __construct(
string $name,
string $street,
string $zip,
string $city,
string $district,
string $country,
string $phone,
string $latitude,
string $longitude,
protected string $name,
protected string $street,
protected string $zip,
protected string $city,
protected string $district,
protected string $country,
protected string $phone,
protected string $latitude,
protected string $longitude,
int $languageUid
) {
$this->name = $name;
$this->street = $street;
$this->zip = $zip;
$this->city = $city;
$this->district = $district;
$this->country = $country;
$this->phone = $phone;
$this->latitude = $this->normalizeGeocoordinate($latitude);
$this->longitude = $this->normalizeGeocoordinate($longitude);
$this->_languageUid = $languageUid;
@ -153,8 +100,7 @@ class Location extends AbstractEntity
|| $this->city !== ''
|| $this->district !== ''
|| $this->country !== ''
|| $this->phone !== ''
;
|| $this->phone !== '';
}
private function generateGlobalId(): string

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Domain\Model;
/*
@ -17,50 +19,21 @@ use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
class Organizer extends AbstractEntity
{
/**
* @var string
*/
protected $name = '';
protected string $name = '';
/**
* @var string
*/
protected $street = '';
protected string $street = '';
/**
* @var string
*/
protected $district = '';
protected string $district = '';
/**
* @var string
*/
protected $city = '';
protected string $city = '';
/**
* @var string
*/
protected $zip = '';
protected string $zip = '';
/**
* @var string
*/
protected $phone = '';
protected string $phone = '';
/**
* @var string
*/
protected $web = '';
protected string $web = '';
/**
* @var string
*/
protected $email = '';
/**
* @var int
*/
protected $_languageUid;
protected string $email = '';
public function getName(): string
{

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Domain\Model;
/*
@ -27,20 +29,14 @@ use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
class Partner extends AbstractEntity
{
/**
* @var string
*/
protected $title = '';
protected string $title = '';
/**
* @var string
*/
protected $link = '';
protected string $link = '';
/**
* @var ObjectStorage<FileReference>
*/
protected $images;
protected ObjectStorage $images;
public function getTitle(): string
{

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Domain\Model;
/*
@ -17,15 +19,7 @@ use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
class Region extends AbstractEntity
{
/**
* @var string
*/
protected $title = '';
/**
* @var int
*/
protected $_languageUid;
protected string $title = '';
public function getTitle(): string
{

View file

@ -28,26 +28,13 @@ use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper;
use TYPO3\CMS\Extbase\Persistence\Repository;
use WerkraumMedia\Events\Domain\Model\Category;
class CategoryRepository extends Repository
final class CategoryRepository extends Repository
{
/**
* @var ConnectionPool
*/
protected $connectionPool;
/**
* @var DataMapper
*/
protected $dataMapper;
public function injectConnectionPool(ConnectionPool $connectionPool): void
{
$this->connectionPool = $connectionPool;
}
public function injectDataMapper(DataMapper $dataMapper): void
{
$this->dataMapper = $dataMapper;
public function __construct(
private readonly ConnectionPool $connectionPool,
private readonly DataMapper $dataMapper,
) {
parent::__construct();
}
/**
@ -88,7 +75,7 @@ class CategoryRepository extends Repository
return $this->dataMapper->map(
Category::class,
$qb->execute()->fetchAll()
$qb->executeQuery()->fetchAll()
);
}
@ -105,10 +92,10 @@ class CategoryRepository extends Repository
$query->getQuerySettings()->setIgnoreEnableFields(true);
$query->getQuerySettings()->setEnableFieldsToBeIgnored(['disabled']);
$query->matching($query->logicalAnd([
$query->matching($query->logicalAnd(
$query->equals('parent', $parentCategory),
$query->equals('title', $title),
]));
));
$query->setLimit(1);

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Domain\Repository;
use DateTimeImmutable;
@ -15,16 +17,12 @@ use UnexpectedValueException;
use WerkraumMedia\Events\Domain\Model\Dto\DateDemand;
use WerkraumMedia\Events\Service\CategoryService;
class DateRepository extends Repository
final class DateRepository extends Repository
{
/**
* @var Context
*/
protected $context;
public function injectContext(Context $context): void
{
$this->context = $context;
public function __construct(
private readonly Context $context
) {
parent::__construct();
}
public function findByUids(string $uids): QueryResult
@ -95,27 +93,27 @@ class DateRepository extends Repository
$now = $now->modify('midnight');
}
$constraints['nowAndFuture'] = $query->logicalOr([
$constraints['nowAndFuture'] = $query->logicalOr(
$query->greaterThanOrEqual('start', $now),
$query->greaterThanOrEqual('end', $now),
]);
);
} elseif ($demand->shouldShowUpcoming()) {
$now = $this->getNow();
$constraints['future'] = $query->logicalAnd([
$constraints['future'] = $query->logicalAnd(
$query->greaterThan('start', $now),
$query->logicalOr([
$query->logicalOr(
$query->equals('end', 0),
$query->greaterThan('end', $now),
]),
]);
),
);
}
if ($demand->getLimit() !== '') {
$query->setLimit((int)$demand->getLimit());
}
$query->matching($query->logicalAnd($constraints));
$query->matching($query->logicalAnd(... $constraints));
if ($demand->getSortBy() && $demand->getSortOrder()) {
$query->setOrderings([$demand->getSortBy() => $demand->getSortOrder()]);
@ -146,8 +144,9 @@ class DateRepository extends Repository
$wordsToSearch[] = $demand->getSearchword();
$constraints = [];
$queryBuilder = $this->objectManager->get(ConnectionPool::class)
->getQueryBuilderForTable('tx_events_domain_model_date');
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable('tx_events_domain_model_date')
;
foreach ($wordsToSearch as $word) {
foreach ($fieldsToSearch as $field) {
@ -155,7 +154,7 @@ class DateRepository extends Repository
}
}
return $query->logicalOr($constraints);
return $query->logicalOr(... $constraints);
}
protected function createCategoryConstraint(
@ -170,7 +169,8 @@ class DateRepository extends Repository
if ($demand->getIncludeSubCategories()) {
$categories = GeneralUtility::makeInstance(CategoryService::class)
->getChildrenCategories($categories);
->getChildrenCategories($categories)
;
}
$categories = GeneralUtility::intExplode(',', $categories, true);
@ -183,10 +183,10 @@ class DateRepository extends Repository
}
if ($demand->getCategoryCombination() === 'or') {
return $query->logicalOr($constraints);
return $query->logicalOr(... $constraints);
}
return $query->logicalAnd($constraints);
return $query->logicalAnd(... $constraints);
}
private function createTimingConstraint(
@ -196,42 +196,42 @@ class DateRepository extends Repository
// Dates might have end of 0 if only start exists.
if ($demand->getStartObject() !== null && $demand->getEndObject() === null) {
return $query->logicalOr([
return $query->logicalOr(
$query->greaterThanOrEqual('start', $demand->getStartObject()),
$query->greaterThanOrEqual('end', $demand->getStartObject()),
]);
);
}
if ($demand->getStartObject() === null && $demand->getEndObject() !== null) {
return $query->logicalOr([
$query->logicalAnd([
return $query->logicalOr(
$query->logicalAnd(
$query->lessThanOrEqual('end', $demand->getEndObject()),
$query->greaterThan('end', 0),
]),
),
$query->lessThanOrEqual('start', $demand->getEndObject()),
]);
);
}
if ($demand->getStartObject() !== null && $demand->getEndObject() !== null) {
return $query->logicalOr([
$query->logicalAnd([
$query->logicalOr([
return $query->logicalOr(
$query->logicalAnd(
$query->logicalOr(
$query->greaterThanOrEqual('start', $demand->getStartObject()),
$query->greaterThanOrEqual('end', $demand->getStartObject()),
]),
$query->logicalOr([
),
$query->logicalOr(
$query->lessThanOrEqual('start', $demand->getEndObject()),
$query->logicalAnd([
$query->logicalAnd(
$query->lessThanOrEqual('end', $demand->getEndObject()),
$query->greaterThan('end', 0),
]),
]),
]),
$query->logicalAnd([
),
),
),
$query->logicalAnd(
$query->lessThanOrEqual('start', $demand->getStartObject()),
$query->greaterThanOrEqual('end', $demand->getEndObject()),
]),
]);
),
);
}
return null;
@ -247,13 +247,14 @@ class DateRepository extends Repository
$constraints[] = $query->contains('event.features', $feature);
}
return $query->logicalAnd($constraints);
return $query->logicalAnd(... $constraints);
}
public function findSearchWord(string $search): array
{
$connection = GeneralUtility::makeInstance(ConnectionPool::class)
->getConnectionForTable('tx_events_domain_model_date');
->getConnectionForTable('tx_events_domain_model_date')
;
$queryBuilder = $connection->createQueryBuilder();
@ -270,9 +271,10 @@ class DateRepository extends Repository
)
)->where(
$queryBuilder->expr()->like('event.title', $queryBuilder->createNamedParameter('%' . $search . '%'))
)->orderBy('tx_events_domain_model_date.start');
)->orderBy('tx_events_domain_model_date.start')
;
return $statement->execute()->fetchAll();
return $statement->executeQuery()->fetchAll();
}
private function createEventConstraint(

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Domain\Repository;
/*
@ -24,7 +26,7 @@ use WerkraumMedia\Events\Domain\Model\Dto\EventDemand;
use WerkraumMedia\Events\Domain\Model\Event;
use WerkraumMedia\Events\Service\CategoryService;
class EventRepository extends Repository
final class EventRepository extends Repository
{
public function findByUids(string $uids): QueryResult
{
@ -55,7 +57,7 @@ class EventRepository extends Repository
$constraints = $this->getConstraints($query, $demand);
if (!empty($constraints)) {
$query->matching($query->logicalAnd($constraints));
$query->matching($query->logicalAnd(... $constraints));
}
if ($demand->getLimit() !== '') {
@ -148,9 +150,9 @@ class EventRepository extends Repository
}
if ($demand->getCategoryCombination() === 'or') {
return $query->logicalOr($constraints);
return $query->logicalOr(... $constraints);
}
return $query->logicalAnd($constraints);
return $query->logicalAnd(... $constraints);
}
public function findSearchWord(string $search): QueryResult

View file

@ -1,11 +1,13 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Domain\Repository;
use TYPO3\CMS\Extbase\Persistence\Repository;
use WerkraumMedia\Events\Domain\Model\Location;
class LocationRepository extends Repository
final class LocationRepository extends Repository
{
public function findOneByGlobalId(string $globalId): ?Location
{

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Domain\Repository;
/*
@ -17,6 +19,6 @@ namespace WerkraumMedia\Events\Domain\Repository;
use TYPO3\CMS\Extbase\Persistence\Repository;
class OrganizerRepository extends Repository
final class OrganizerRepository extends Repository
{
}

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Domain\Repository;
/*
@ -17,6 +19,6 @@ namespace WerkraumMedia\Events\Domain\Repository;
use TYPO3\CMS\Extbase\Persistence\Repository;
class RegionRepository extends Repository
final class RegionRepository extends Repository
{
}

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Events\Controller;
use TYPO3\CMS\Core\Pagination\PaginationInterface;
@ -9,41 +11,17 @@ use WerkraumMedia\Events\Domain\Model\Dto\DateDemand;
final class DateListVariables
{
/**
* @var array
*/
private $search;
/**
* @var DateDemand
*/
private $demand;
/**
* @var QueryResult<Date>
*/
private $dates;
/**
* @var PaginationInterface
*/
private $pagination;
/**
* @var array
*/
private $variables = [];
private array $variables = [];
public function __construct(
array $search,
DateDemand $demand,
QueryResult $dates,
PaginationInterface $pagination
private readonly array $search,
private readonly DateDemand $demand,
/**
* @var QueryResult<Date>
*/
private readonly QueryResult $dates,
private readonly PaginationInterface $pagination
) {
$this->search = $search;
$this->demand = $demand;
$this->dates = $dates;
$this->pagination = $pagination;
}
public function getSearch(): array
@ -64,21 +42,19 @@ final class DateListVariables
return $this->dates;
}
/**
* @param mixed $value
*/
public function addVariable(string $key, $value): void
public function addVariable(string $key, mixed $value): void
{
$this->variables[$key] = $value;
}
public function getVariablesForView(): array
{
return array_merge([
return [
'search' => $this->search,
'demand' => $this->demand,
'dates' => $this->dates,
'pagination' => $this->pagination,
], $this->variables);
...$this->variables,
];
}
}

View file

@ -1,59 +1,30 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Events\Controller;
use TYPO3\CMS\Extbase\Domain\Model\Category;
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
use WerkraumMedia\Events\Domain\Model\Category;
use WerkraumMedia\Events\Domain\Model\Dto\DateDemand;
use WerkraumMedia\Events\Domain\Model\Region;
class DateSearchVariables
final class DateSearchVariables
{
/**
* @var array
*/
private $search;
/**
* @var DateDemand
*/
private $demand;
/**
* @var QueryResultInterface<Region>
*/
private $regions;
/**
* @var array<Category>
*/
private $categories;
/**
* @var array<Category>
*/
private $features;
/**
* @var array
*/
private $variables = [];
private array $variables = [];
/**
* @param QueryResultInterface<Region> $regions
* @param array<Category> $categories
* @param array<Category> $features
*/
public function __construct(
array $search,
DateDemand $demand,
QueryResultInterface $regions,
array $categories,
array $features
private readonly array $search,
private readonly DateDemand $demand,
private readonly QueryResultInterface $regions,
private readonly array $categories,
private readonly array $features
) {
$this->search = $search;
$this->demand = $demand;
$this->regions = $regions;
$this->categories = $categories;
$this->features = $features;
}
public function getSearch(): array
@ -84,22 +55,20 @@ class DateSearchVariables
return $this->features;
}
/**
* @param mixed $value
*/
public function addVariable(string $key, $value): void
public function addVariable(string $key, mixed $value): void
{
$this->variables[$key] = $value;
}
public function getVariablesForView(): array
{
return array_merge([
return [
'search' => $this->search,
'demand' => $this->demand,
'regions' => $this->regions,
'categories' => $this->categories,
'features' => $this->features,
], $this->variables);
...$this->variables,
];
}
}

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Extbase;
/*
@ -26,37 +28,22 @@ use TYPO3\CMS\Extbase\Event\Persistence\AfterObjectThawedEvent;
use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper;
use WerkraumMedia\Events\Domain\Model\Date;
class AddSpecialProperties
final class AddSpecialProperties
{
/**
* @var ConnectionPool
*/
private $connectionPool;
/**
* @var DataMapper
*/
private $dataMapper;
/**
* Internal info to speed things up if we know there are none.
*
* @var bool
*/
private $doPostponedDatesExist = true;
private bool $doPostponedDatesExist = true;
public function __construct(
ConnectionPool $connectionPool,
DataMapper $dataMapper
private readonly ConnectionPool $connectionPool,
private readonly DataMapper $dataMapper
) {
$this->connectionPool = $connectionPool;
$this->dataMapper = $dataMapper;
$qb = $this->connectionPool->getQueryBuilderForTable('tx_events_domain_model_date');
$qb->count('uid');
$qb->from('tx_events_domain_model_date');
$qb->where($qb->expr()->gt('postponed_date', $qb->createNamedParameter(0)));
$this->doPostponedDatesExist = $qb->execute()->fetchColumn() > 0;
$this->doPostponedDatesExist = $qb->executeQuery()->fetchOne() > 0;
}
public function __invoke(AfterObjectThawedEvent $event): void
@ -85,7 +72,7 @@ class AddSpecialProperties
$qb->where($qb->expr()->eq('postponed_date', $uidOfReferencedDate));
$qb->setMaxResults(1);
$result = $qb->execute()->fetch();
$result = $qb->executeQuery()->fetch();
if ($result === false) {
return null;

View file

@ -5,11 +5,11 @@ declare(strict_types=1);
namespace WerkraumMedia\Events\Pagination;
use TYPO3\CMS\Core\Pagination\PaginationInterface;
use TYPO3\CMS\Core\Pagination\SlidingWindowPagination;
use TYPO3\CMS\Extbase\Pagination\QueryResultPaginator;
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
use WerkraumMedia\Events\Backports\V12\Pagination\SlidingWindowPagination;
class Factory
final class Factory
{
public function create(
int $currentPage,

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Service;
use TYPO3\CMS\Core\Cache\CacheManager;
@ -9,13 +11,11 @@ use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\TimeTracker\TimeTracker;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class CategoryService
final class CategoryService
{
/** @var TimeTracker */
protected $timeTracker;
private TimeTracker $timeTracker;
/** @var FrontendInterface */
protected $cache;
private FrontendInterface $cache;
public function __construct()
{
@ -28,7 +28,6 @@ class CategoryService
* and using the caching framework to save some queries
*
* @param string $idList list of category ids to start
* @param int $counter
*
* @return string comma separated list of category ids
*/
@ -66,7 +65,8 @@ class CategoryService
}
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable('sys_category');
->getQueryBuilderForTable('sys_category')
;
$res = $queryBuilder
->select('uid')
->from('sys_category')
@ -74,7 +74,8 @@ class CategoryService
'parent',
$queryBuilder->createNamedParameter(explode(',', $idList), Connection::PARAM_INT_ARRAY)
))
->execute();
->executeQuery()
;
while ($row = $res->fetch()) {
if (is_array($row) === false) {
@ -96,16 +97,13 @@ class CategoryService
/**
* Fetch ids again from DB to avoid false positives
*
* @param string $idList
*
* @return string
*/
protected function getUidListFromRecords(string $idList): string
{
$list = [];
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable('sys_category');
->getQueryBuilderForTable('sys_category')
;
$rows = $queryBuilder
->select('uid')
->from('sys_category')
@ -113,8 +111,9 @@ class CategoryService
'uid',
$queryBuilder->createNamedParameter(explode(',', $idList), Connection::PARAM_INT_ARRAY)
))
->execute()
->fetchAll();
->executeQuery()
->fetchAll()
;
foreach ($rows as $row) {
if (is_array($row) === false) {
continue;

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Service\Cleanup;
/*
@ -21,24 +23,20 @@ namespace WerkraumMedia\Events\Service\Cleanup;
* 02110-1301, USA.
*/
use DateTimeImmutable;
use PDO;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
class Database
final class Database
{
/**
* @var ConnectionPool
*/
private $connectionPool;
private const DATE_TABLE = 'tx_events_domain_model_date';
private const EVENT_TABLE = 'tx_events_domain_model_event';
private const ORGANIZER_TABLE = 'tx_events_domain_model_organizer';
public function __construct(
ConnectionPool $connectionPool
private readonly ConnectionPool $connectionPool
) {
$this->connectionPool = $connectionPool;
}
public function truncateTables(): void
@ -52,48 +50,46 @@ class Database
foreach ($tableNames as $tableName) {
$this->connectionPool
->getConnectionForTable($tableName)
->truncate($tableName);
->truncate($tableName)
;
}
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('sys_category_record_mm');
$queryBuilder->delete('sys_category_record_mm')
->where($queryBuilder->expr()->like(
'tablenames',
$queryBuilder->createNamedParameter('tx_events_domain_model_%')
))
->execute();
$queryBuilder->delete('sys_category_record_mm')->where($queryBuilder->expr()->like(
'tablenames',
$queryBuilder->createNamedParameter('tx_events_domain_model_%')
))->executeStatement();
}
public function deletePastDates(): void
{
$queryBuilder = $this->connectionPool
->getConnectionForTable(self::DATE_TABLE)
->createQueryBuilder();
->createQueryBuilder()
;
$queryBuilder->getRestrictions()->removeAll();
$midnightToday = new \DateTimeImmutable('midnight today');
$queryBuilder->delete(self::DATE_TABLE)
->where($queryBuilder->expr()->lte(
'end',
$queryBuilder->createNamedParameter($midnightToday->format('U'))
))
->execute();
$midnightToday = new DateTimeImmutable('midnight today');
$queryBuilder->delete(self::DATE_TABLE)->where($queryBuilder->expr()->lte(
'end',
$queryBuilder->createNamedParameter($midnightToday->format('U'))
))->executeStatement();
}
public function deleteEventsWithoutDates(): void
{
$queryBuilder = $this->connectionPool
->getConnectionForTable(self::EVENT_TABLE)
->createQueryBuilder();
->createQueryBuilder()
;
$queryBuilder->getRestrictions()->removeAll();
$recordUids = $queryBuilder->select('event.uid')
->from(self::EVENT_TABLE, 'event')
->leftJoin('event', self::DATE_TABLE, 'date', $queryBuilder->expr()->eq('date.event', 'event.uid'))
->where($queryBuilder->expr()->isNull('date.uid'))
->execute()
->fetchAll(\PDO::FETCH_COLUMN);
->leftJoin('event', self::DATE_TABLE, 'date', $queryBuilder->expr()->eq('date.event', 'event.uid'))->where($queryBuilder->expr()->isNull('date.uid'))->executeQuery()
->fetchAll(PDO::FETCH_COLUMN)
;
$queryBuilder = $this->connectionPool->getQueryBuilderForTable(self::EVENT_TABLE);
$queryBuilder->delete(self::EVENT_TABLE);
@ -101,20 +97,15 @@ class Database
'uid',
$queryBuilder->createNamedParameter($recordUids, Connection::PARAM_INT_ARRAY)
));
$queryBuilder->execute();
$queryBuilder->executeStatement();
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('sys_category_record_mm');
$queryBuilder->delete('sys_category_record_mm')
->where($queryBuilder->expr()->andX(
$queryBuilder->expr()->like(
'tablenames',
$queryBuilder->createNamedParameter('tx_events_domain_model_%')
),
$queryBuilder->expr()->in(
'uid_foreign',
$queryBuilder->createNamedParameter($recordUids, Connection::PARAM_INT_ARRAY)
)
))
->execute();
$queryBuilder->delete('sys_category_record_mm')->where($queryBuilder->expr()->and($queryBuilder->expr()->like(
'tablenames',
$queryBuilder->createNamedParameter('tx_events_domain_model_%')
), $queryBuilder->expr()->in(
'uid_foreign',
$queryBuilder->createNamedParameter($recordUids, Connection::PARAM_INT_ARRAY)
)))->executeStatement();
}
}

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Service\Cleanup;
/*
@ -21,28 +23,17 @@ namespace WerkraumMedia\Events\Service\Cleanup;
* 02110-1301, USA.
*/
use PDO;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Resource\StorageRepository;
class Files
final class Files
{
/**
* @var ConnectionPool
*/
private $connectionPool;
/**
* @var StorageRepository
*/
private $storageRepository;
public function __construct(
ConnectionPool $connectionPool,
StorageRepository $storageRepository
private readonly ConnectionPool $connectionPool,
private readonly StorageRepository $storageRepository
) {
$this->connectionPool = $connectionPool;
$this->storageRepository = $storageRepository;
}
public function deleteDangling(): void
@ -54,7 +45,8 @@ class Files
private function markFileReferencesDeletedIfForeignRecordIsMissing(): void
{
$referencesQuery = $this->connectionPool
->getQueryBuilderForTable('sys_file_reference');
->getQueryBuilderForTable('sys_file_reference')
;
$referencesQuery->getRestrictions()->removeAll();
$referencesQuery->select(
'uid',
@ -70,7 +62,7 @@ class Files
);
// Remove file relations removed via import
$referencesQuery->orWhere(
$referencesQuery->expr()->andX(
$referencesQuery->expr()->and(
$referencesQuery->expr()->eq(
'tablenames',
$referencesQuery->createNamedParameter('')
@ -92,7 +84,7 @@ class Files
$referencesQuery->orderBy('tablenames');
$referencesQuery->addOrderBy('uid_foreign');
$references = $referencesQuery->execute();
$references = $referencesQuery->executeQuery();
$uidsPerTable = [];
$referenceUidsToMarkAsDeleted = [];
@ -116,10 +108,13 @@ class Files
$queryBuilder->select('uid');
$queryBuilder->from($tableName);
$queryBuilder->where($queryBuilder->expr()->in('uid', $records));
$referenceUidsToMarkAsDeleted = array_merge(
$referenceUidsToMarkAsDeleted,
array_keys(array_diff($records, $queryBuilder->execute()->fetchAll(\PDO::FETCH_COLUMN)))
);
$referenceUidsToMarkAsDeleted = [
...$referenceUidsToMarkAsDeleted,
...array_keys(array_diff(
$records,
$queryBuilder->executeQuery()->fetchAll(PDO::FETCH_COLUMN)
)),
];
}
if ($referenceUidsToMarkAsDeleted === []) {
@ -130,7 +125,7 @@ class Files
$updateQuery->update('sys_file_reference');
$updateQuery->where($updateQuery->expr()->in('uid', $referenceUidsToMarkAsDeleted));
$updateQuery->set('deleted', '1');
$updateQuery->execute();
$updateQuery->executeStatement();
}
private function deleteFilesWithoutProperReference(): void
@ -160,14 +155,16 @@ class Files
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('sys_file');
$queryBuilder->delete('sys_file')
->where('uid in (:uids)')
->setParameter(':uids', $uids, Connection::PARAM_INT_ARRAY)
->execute();
->setParameter('uids', $uids, Connection::PARAM_INT_ARRAY)
->executeStatement()
;
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('sys_file_metadata');
$queryBuilder->delete('sys_file_metadata')
->where('file in (:uids)')
->setParameter(':uids', $uids, Connection::PARAM_INT_ARRAY)
->execute();
->setParameter('uids', $uids, Connection::PARAM_INT_ARRAY)
->executeStatement()
;
$this->deleteReferences();
}
@ -179,7 +176,7 @@ class Files
$queryBuilder
->delete('sys_file_reference')
->where(
$queryBuilder->expr()->orX(
$queryBuilder->expr()->or(
$queryBuilder->expr()->like(
'tablenames',
$queryBuilder->createNamedParameter('tx_events_domain_model_%')
@ -195,7 +192,7 @@ class Files
1
))
;
$queryBuilder->execute();
$queryBuilder->executeStatement();
}
/**
@ -225,7 +222,7 @@ class Files
->groupBy('file.uid')
;
return $queryBuilder->execute()->fetchAllAssociativeIndexed();
return $queryBuilder->executeQuery()->fetchAllAssociativeIndexed();
}
/**
@ -249,13 +246,13 @@ class Files
))
;
foreach ($queryBuilder->execute() as $reference) {
foreach ($queryBuilder->executeQuery()->iterateAssociative() as $reference) {
$file = [];
$fileUid = (int)$reference['uid_local'];
if (
(
str_starts_with($reference['tablenames'], 'tx_events_domain_model_')
str_starts_with((string)$reference['tablenames'], 'tx_events_domain_model_')
|| $reference['tablenames'] === ''
) && $reference['deleted'] == 1
) {

View file

@ -1,26 +1,18 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Service;
use WerkraumMedia\Events\Service\Cleanup\Database;
use WerkraumMedia\Events\Service\Cleanup\Files;
class CleanupService
final class CleanupService
{
/**
* @var Database
*/
private $database;
/**
* @var Files
*/
private $files;
public function __construct(Database $database, Files $files)
{
$this->database = $database;
$this->files = $files;
public function __construct(
private readonly Database $database,
private readonly Files $files
) {
}
public function deleteAllData(): void

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Service;
/*
@ -67,49 +69,22 @@ use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
*
* - Event->getPages()
*/
class DataProcessingForModels implements SingletonInterface
final class DataProcessingForModels implements SingletonInterface
{
/**
* @var ContentObjectRenderer
*/
private $cObject;
private readonly ContentObjectRenderer $cObject;
/**
* @var ContentDataProcessor
*/
private $processorHandler;
private readonly Connection $connection;
/**
* @var Connection
*/
private $connection;
/**
* @var DataMapFactory
*/
private $dataMapFactory;
/**
* @var ConfigurationManagerInterface|null
*/
private $configurationManager;
/**
* @var TypoScriptService
*/
private $typoScriptService;
private ?ConfigurationManagerInterface $configurationManager = null;
public function __construct(
ContentDataProcessor $processorHandler,
private readonly ContentDataProcessor $processorHandler,
ConnectionPool $connectionPool,
DataMapFactory $dataMapFactory,
TypoScriptService $typoScriptService
private readonly DataMapFactory $dataMapFactory,
private readonly TypoScriptService $typoScriptService
) {
$this->cObject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
$this->processorHandler = $processorHandler;
$this->connection = $connectionPool->getConnectionByName('Default');
$this->dataMapFactory = $dataMapFactory;
$this->typoScriptService = $typoScriptService;
}
/**
@ -148,7 +123,7 @@ class DataProcessingForModels implements SingletonInterface
private function getTable(AbstractEntity $entity): string
{
$dataMap = $this->dataMapFactory->buildDataMap(get_class($entity));
$dataMap = $this->dataMapFactory->buildDataMap($entity::class);
return $dataMap->getTableName();
}
@ -158,7 +133,7 @@ class DataProcessingForModels implements SingletonInterface
return [];
}
$className = get_class($entity);
$className = $entity::class;
$settings = $this->configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS
);

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Service;
use Exception;
@ -9,7 +11,6 @@ use TYPO3\CMS\Core\Log\LogManager;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManager;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
use WerkraumMedia\Events\Caching\CacheManager;
use WerkraumMedia\Events\Domain\Model\Event;
@ -31,148 +32,36 @@ use WerkraumMedia\Events\Service\DestinationDataImportService\FilesAssignment;
use WerkraumMedia\Events\Service\DestinationDataImportService\LocationAssignment;
use WerkraumMedia\Events\Service\DestinationDataImportService\Slugger;
class DestinationDataImportService
final class DestinationDataImportService
{
/**
* @var Import
*/
private $import;
private Import $import;
/**
* @var Event
*/
private $tmpCurrentEvent;
private Event $tmpCurrentEvent;
/**
* @var Logger
*/
private $logger;
/**
* @var EventRepository
*/
private $eventRepository;
/**
* @var OrganizerRepository
*/
private $organizerRepository;
/**
* @var DateRepository
*/
private $dateRepository;
/**
* @var ConfigurationManager
*/
private $configurationManager;
/**
* @var ObjectManager
*/
private $objectManager;
/**
* @var PersistenceManager
*/
private $persistenceManager;
/**
* @var DataFetcher
*/
private $dataFetcher;
/**
* @var DatesFactory
*/
private $datesFactory;
/**
* @var FilesAssignment
*/
private $filesAssignment;
/**
* @var CategoriesAssignment
*/
private $categoriesAssignment;
/**
* @var LocationAssignment
*/
private $locationAssignment;
/**
* @var Slugger
*/
private $slugger;
/**
* @var CacheManager
*/
private $cacheManager;
/**
* @var DataHandler
*/
private $dataHandler;
/**
* @var EventDispatcher
*/
private $eventDispatcher;
/**
* ImportService constructor.
*
* @param EventRepository $eventRepository
* @param OrganizerRepository $organizerRepository
* @param DateRepository $dateRepository
* @param ConfigurationManager $configurationManager
* @param PersistenceManager $persistenceManager
* @param ObjectManager $objectManager
* @param DataFetcher $dataFetcher
* @param FilesAssignment $filesAssignment
* @param CategoriesAssignment $categoriesAssignment
* @param LocationAssignment $locationAssignment
* @param Slugger $slugger
* @param CacheManager $cacheManager
* @param DataHandler $dataHandler
* @param EventDispatcher $eventDispatcher
*/
public function __construct(
EventRepository $eventRepository,
OrganizerRepository $organizerRepository,
DateRepository $dateRepository,
ConfigurationManager $configurationManager,
PersistenceManager $persistenceManager,
ObjectManager $objectManager,
DataFetcher $dataFetcher,
DatesFactory $datesFactory,
FilesAssignment $filesAssignment,
CategoriesAssignment $categoriesAssignment,
LocationAssignment $locationAssignment,
Slugger $slugger,
CacheManager $cacheManager,
DataHandler $dataHandler,
EventDispatcher $eventDispatcher
private readonly EventRepository $eventRepository,
private readonly OrganizerRepository $organizerRepository,
private readonly DateRepository $dateRepository,
private readonly ConfigurationManager $configurationManager,
private readonly PersistenceManager $persistenceManager,
private readonly DataFetcher $dataFetcher,
private readonly DatesFactory $datesFactory,
private readonly FilesAssignment $filesAssignment,
private readonly CategoriesAssignment $categoriesAssignment,
private readonly LocationAssignment $locationAssignment,
private readonly Slugger $slugger,
private readonly CacheManager $cacheManager,
private readonly DataHandler $dataHandler,
private readonly EventDispatcher $eventDispatcher
) {
$this->eventRepository = $eventRepository;
$this->organizerRepository = $organizerRepository;
$this->dateRepository = $dateRepository;
$this->configurationManager = $configurationManager;
$this->persistenceManager = $persistenceManager;
$this->objectManager = $objectManager;
$this->dataFetcher = $dataFetcher;
$this->datesFactory = $datesFactory;
$this->filesAssignment = $filesAssignment;
$this->categoriesAssignment = $categoriesAssignment;
$this->locationAssignment = $locationAssignment;
$this->slugger = $slugger;
$this->cacheManager = $cacheManager;
$this->dataHandler = $dataHandler;
$this->eventDispatcher = $eventDispatcher;
}
public function import(
@ -194,12 +83,12 @@ class DestinationDataImportService
// Set Configuration
$this->configurationManager->setConfiguration(array_merge($frameworkConfiguration, $persistenceConfiguration));
$this->logger = GeneralUtility::makeInstance(LogManager::class)->getLogger(__CLASS__);
$this->logger = GeneralUtility::makeInstance(LogManager::class)->getLogger(self::class);
$this->logger->info('Starting Destination Data Import Service');
try {
$data = $this->dataFetcher->fetchSearchResult($import);
} catch (Exception $e) {
} catch (Exception) {
$this->logger->error('Could not receive data.');
return 1;
}
@ -215,7 +104,7 @@ class DestinationDataImportService
$selectedRegion = $this->import->getRegion();
foreach ($data['items'] as $event) {
$this->logger->info('Processing event ' . substr($event['title'], 0, 20));
$this->logger->info('Processing event ' . substr((string)$event['title'], 0, 20));
// Event already exists? If not create one!
$this->tmpCurrentEvent = $this->getOrCreateEvent($event['global_id'], $event['title']);
@ -230,7 +119,7 @@ class DestinationDataImportService
}
// Set Title
$this->tmpCurrentEvent->setTitle(substr($event['title'], 0, 254));
$this->tmpCurrentEvent->setTitle(substr((string)$event['title'], 0, 254));
// Set Highlight (Is only set in rest if true)
if ($event['highlight'] ?? false) {
@ -382,7 +271,7 @@ class DestinationDataImportService
$this->tmpCurrentEvent->setOrganizer($tmpOrganizer);
continue;
}
$tmpOrganizer = $this->objectManager->get(Organizer::class);
$tmpOrganizer = GeneralUtility::makeInstance(Organizer::class);
$tmpOrganizer->setLanguageUid(-1);
$tmpOrganizer->setName($address['name'] ?? '');
$tmpOrganizer->setCity($address['city'] ?? '');
@ -398,9 +287,6 @@ class DestinationDataImportService
}
}
/**
* @param array $media
*/
private function setSocial(array $media): void
{
foreach ($media as $link) {
@ -470,13 +356,13 @@ class DestinationDataImportService
}
if ($text['rel'] == 'details' && $text['type'] == 'text/plain') {
$this->tmpCurrentEvent->setDetails(str_replace("\n\n", "\n", $text['value']));
$this->tmpCurrentEvent->setDetails(str_replace("\n\n", "\n", (string)$text['value']));
}
if ($text['rel'] == 'teaser' && $text['type'] == 'text/plain') {
$this->tmpCurrentEvent->setTeaser(str_replace("\n\n", "\n", $text['value']));
$this->tmpCurrentEvent->setTeaser(str_replace("\n\n", "\n", (string)$text['value']));
}
if ($text['rel'] == 'PRICE_INFO' && $text['type'] == 'text/plain') {
$this->tmpCurrentEvent->setPriceInfo(str_replace("\n\n", "\n", $text['value']));
$this->tmpCurrentEvent->setPriceInfo(str_replace("\n\n", "\n", (string)$text['value']));
}
}
}
@ -494,7 +380,7 @@ class DestinationDataImportService
// New event is created
$this->logger->info(substr($title, 0, 20) . ' does not exist');
$event = $this->objectManager->get(Event::class);
$event = GeneralUtility::makeInstance(Event::class);
// Create event and persist
$event->setGlobalId($globalId);
$this->eventRepository->add($event);

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Service\DestinationDataImportService;
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
@ -14,24 +16,12 @@ use WerkraumMedia\Events\Service\DestinationDataImportService\CategoriesAssignme
* Categories mean TYPO3 sys_category records.
* Those are used for multiple records within destination data. E.g. categories or features.
*/
class CategoriesAssignment
final class CategoriesAssignment
{
/**
* @var CategoryRepository
*/
private $repository;
/**
* @var PersistenceManager
*/
private $persistenceManager;
public function __construct(
CategoryRepository $repository,
PersistenceManager $persistenceManager
private readonly CategoryRepository $repository,
private readonly PersistenceManager $persistenceManager
) {
$this->repository = $repository;
$this->persistenceManager = $persistenceManager;
}
/**

View file

@ -1,41 +1,19 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Service\DestinationDataImportService\CategoriesAssignment;
use WerkraumMedia\Events\Domain\Model\Category;
class Import
final class Import
{
/**
* @var Category|null
*/
private $parentCategory;
/**
* @var int|null
*/
private $pid;
/**
* @var array
*/
private $categoryTitles;
/**
* @var bool
*/
private $hideByDefault;
public function __construct(
?Category $parentCategory,
?int $pid,
array $categoryTitles,
bool $hideByDefault = false
private readonly ?Category $parentCategory,
private readonly ?int $pid,
private readonly array $categoryTitles,
private readonly bool $hideByDefault = false
) {
$this->parentCategory = $parentCategory;
$this->pid = $pid;
$this->categoryTitles = $categoryTitles;
$this->hideByDefault = $hideByDefault;
}
public function getParentCategory(): ?Category

View file

@ -1,12 +1,15 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Service\DestinationDataImportService;
use Exception;
use GuzzleHttp\ClientInterface as GuzzleClientInterface;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Core\Log\Logger;
use Psr\Log\LoggerInterface;
use TYPO3\CMS\Core\Log\LogManager;
use WerkraumMedia\Events\Domain\Model\Import;
@ -16,39 +19,17 @@ use WerkraumMedia\Events\Domain\Model\Import;
* Only partially migrated from service to here.
* Further calls need to be migrated.
*/
class DataFetcher
final class DataFetcher
{
/**
* @var UrlFactory
*/
private $urlFactory;
/**
* @var RequestFactoryInterface
*/
private $requestFactory;
/**
* @var GuzzleClientInterface
*/
private $client;
/**
* @var Logger
*/
private $logger;
private readonly LoggerInterface $logger;
public function __construct(
UrlFactory $urlFactory,
private readonly UrlFactory $urlFactory,
LogManager $logManager,
RequestFactoryInterface $requestFactory,
GuzzleClientInterface $client
private readonly RequestFactoryInterface $requestFactory,
private readonly GuzzleClientInterface $client
) {
$this->urlFactory = $urlFactory;
$this->requestFactory = $requestFactory;
$this->client = $client;
$this->logger = $logManager->getLogger(__CLASS__);
$this->logger = $logManager->getLogger(self::class);
}
public function fetchSearchResult(Import $import): array
@ -76,9 +57,9 @@ class DataFetcher
$jsonContent = $response->getBody()->__toString();
$jsonResponse = json_decode($jsonContent, true);
$jsonResponse = json_decode($jsonContent, true, 512, JSON_THROW_ON_ERROR);
if (is_array($jsonResponse) === false) {
throw new \Exception('No valid JSON fetched, got: "' . $jsonContent . '".', 1639495835);
throw new Exception('No valid JSON fetched, got: "' . $jsonContent . '".', 1639495835);
}
$this->logger->info('Received data with ' . count($jsonResponse['items']) . ' items');

View file

@ -23,23 +23,20 @@ declare(strict_types=1);
namespace WerkraumMedia\Events\Service\DestinationDataImportService;
use Psr\Log\LoggerInterface;
use TYPO3\CMS\Core\DataHandling\DataHandler as Typo3DataHandler;
use TYPO3\CMS\Core\Log\Logger;
use TYPO3\CMS\Core\Log\LogManager;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use WerkraumMedia\Events\Service\DestinationDataImportService\DataHandler\Assignment;
final class DataHandler
{
/**
* @var Logger
*/
private $logger;
private readonly LoggerInterface $logger;
public function __construct(
LogManager $logManager
) {
$this->logger = $logManager->getLogger(__CLASS__);
$this->logger = $logManager->getLogger(self::class);
}
public function storeAssignments(

View file

@ -28,31 +28,26 @@ use TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject;
final class Assignment
{
/**
* @var int
*/
private $uid;
/**
* @var string
*/
private $columnName;
private readonly int $uid;
/**
* @var int[]
*/
private $uids;
private readonly array $uids;
/**
* @param AbstractDomainObject[] $assignments
*/
public function __construct(
int $uid,
string $columnName,
?int $uid,
private readonly string $columnName,
array $assignments
) {
if (is_int($uid) === false) {
throw new InvalidArgumentException('Only integer allowed as uid, need a persisted entity.', 1699352008);
}
$this->uid = $uid;
$this->columnName = $columnName;
$this->uids = array_map(static function (AbstractDomainObject $model): int {
$uid = $model->getUid();
if (is_int($uid) === false) {

View file

@ -1,50 +1,42 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Service\DestinationDataImportService;
use DateInterval;
use DatePeriod;
use DateTimeImmutable;
use DateTimeZone;
use Generator;
use Psr\Log\LoggerInterface;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Log\Logger;
use TYPO3\CMS\Core\Log\LogManager;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManager;
use WerkraumMedia\Events\Domain\Model\Date;
class DatesFactory
final class DatesFactory
{
/**
* @var Context
*/
private $context;
/**
* @var ConfigurationManager
*/
private $configurationManager;
/**
* @var Logger
*/
private $logger;
private readonly LoggerInterface $logger;
public function __construct(
Context $context,
ConfigurationManager $configurationManager,
private readonly Context $context,
private readonly ConfigurationManager $configurationManager,
LogManager $logManager
) {
$this->context = $context;
$this->configurationManager = $configurationManager;
$this->logger = $logManager->getLogger(__CLASS__);
$this->logger = $logManager->getLogger(self::class);
}
/**
* @return \Generator<Date>
* @return Generator<Date>
*/
public function createDates(
array $timeIntervals,
bool $canceled
): \Generator {
): Generator {
foreach ($timeIntervals as $date) {
$dates = $this->createDate($date, $canceled);
if (!$dates instanceof \Generator) {
if (!$dates instanceof Generator) {
return null;
}
@ -55,12 +47,12 @@ class DatesFactory
}
/**
* @return \Generator<Date>|null
* @return Generator<Date>|null
*/
private function createDate(
array $date,
bool $canceled
): ?\Generator {
): ?Generator {
if ($this->isDateSingleDate($date)) {
$this->logger->info('Is single date', ['date' => $date]);
return $this->createSingleDate($date, $canceled);
@ -99,24 +91,24 @@ class DatesFactory
}
/**
* @return \Generator<Date>
* @return Generator<Date>
*/
private function createSingleDate(
array $date,
bool $canceled
): \Generator {
if (new \DateTimeImmutable($date['start']) > $this->getToday()) {
): Generator {
if (new DateTimeImmutable($date['start']) > $this->getToday()) {
yield Date::createFromDestinationDataDate($date, $canceled);
}
}
/**
* @return \Generator<Date>|null
* @return Generator<Date>|null
*/
private function createDateFromInterval(
array $date,
bool $canceled
): ?\Generator {
): ?Generator {
$date = $this->ensureRepeatUntil($date);
if ($date['freq'] == 'Daily') {
@ -149,19 +141,19 @@ class DatesFactory
}
/**
* @return \Generator<Date>
* @return Generator<Date>
*/
private function createDailyDates(
array $date,
bool $canceled
): \Generator {
): Generator {
$today = $this->getToday();
$timeZone = new \DateTimeZone($date['tz']);
$start = new \DateTimeImmutable($date['start'], $timeZone);
$end = new \DateTimeImmutable($date['end'], $timeZone);
$until = new \DateTimeImmutable($date['repeatUntil'], $timeZone);
$timeZone = new DateTimeZone($date['tz']);
$start = new DateTimeImmutable($date['start'], $timeZone);
$end = new DateTimeImmutable($date['end'], $timeZone);
$until = new DateTimeImmutable($date['repeatUntil'], $timeZone);
$period = new \DatePeriod($start, new \DateInterval('P1D'), $until);
$period = new DatePeriod($start, new DateInterval('P1D'), $until);
foreach ($period as $day) {
$day = $day->setTimezone($timeZone);
if ($day < $today) {
@ -179,23 +171,23 @@ class DatesFactory
}
/**
* @return \Generator<Date>
* @return Generator<Date>
*/
private function createWeeklyDates(
array $date,
bool $canceled
): \Generator {
): Generator {
$today = $this->getToday();
$timeZone = new \DateTimeZone($date['tz']);
$start = new \DateTimeImmutable($date['start'], $timeZone);
$end = new \DateTimeImmutable($date['end'], $timeZone);
$until = new \DateTimeImmutable($date['repeatUntil'], $timeZone);
$timeZone = new DateTimeZone($date['tz']);
$start = new DateTimeImmutable($date['start'], $timeZone);
$end = new DateTimeImmutable($date['end'], $timeZone);
$until = new DateTimeImmutable($date['repeatUntil'], $timeZone);
foreach ($date['weekdays'] as $day) {
$dateToUse = $start->modify($day);
$dateToUse = $dateToUse->setTime((int)$start->format('H'), (int)$start->format('i'));
$period = new \DatePeriod($dateToUse, new \DateInterval('P1W'), $until);
$period = new DatePeriod($dateToUse, new DateInterval('P1W'), $until);
foreach ($period as $day) {
$day = $day->setTimezone($timeZone);
if ($day < $today) {
@ -214,9 +206,9 @@ class DatesFactory
}
private function createDateFromStartAndEnd(
\DateTimeImmutable $dateToUse,
\DateTimeImmutable $start,
\DateTimeImmutable $end,
DateTimeImmutable $dateToUse,
DateTimeImmutable $start,
DateTimeImmutable $end,
bool $canceled
): Date {
return Date::createFromDestinationData(
@ -226,11 +218,11 @@ class DatesFactory
);
}
private function getToday(): \DateTimeImmutable
private function getToday(): DateTimeImmutable
{
$today = $this->context->getPropertyFromAspect('date', 'full', new \DateTimeImmutable());
if (!$today instanceof \DateTimeImmutable) {
$today = new \DateTimeImmutable();
$today = $this->context->getPropertyFromAspect('date', 'full', new DateTimeImmutable());
if (!$today instanceof DateTimeImmutable) {
$today = new DateTimeImmutable();
}
return $today->modify('midnight');

View file

@ -29,24 +29,18 @@ use WerkraumMedia\Events\Domain\Model\Event;
final class CategoriesAssignEvent
{
/**
* @var Event
*/
private $event;
/**
* @var ObjectStorage<Category>
*/
private $categories;
private ObjectStorage $categories;
/**
* @param ObjectStorage<Category> $categories
*/
public function __construct(
Event $event,
private readonly Event $event,
ObjectStorage $categories
) {
$this->event = $event;
$this->setCategories($categories);
}

View file

@ -27,22 +27,10 @@ use WerkraumMedia\Events\Domain\Model\Event;
final class EventImportEvent
{
/**
* @var Event
*/
private $existingEvent;
/**
* @var Event
*/
private $eventToImport;
public function __construct(
Event $existingEvent,
Event $eventToImport
private readonly Event $existingEvent,
private readonly Event $eventToImport
) {
$this->existingEvent = $existingEvent;
$this->eventToImport = $eventToImport;
}
public function getBaseEvent(): Event

View file

@ -25,6 +25,7 @@ namespace WerkraumMedia\Events\Service\DestinationDataImportService;
use Exception;
use Psr\Log\LoggerInterface;
use SplFileInfo;
use TYPO3\CMS\Core\Log\LogManager;
use TYPO3\CMS\Core\Resource\DuplicationBehavior;
use TYPO3\CMS\Core\Resource\File;
@ -36,38 +37,17 @@ use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
use WerkraumMedia\Events\Domain\Model\Event;
use WerkraumMedia\Events\Domain\Model\Import;
class FilesAssignment
final class FilesAssignment
{
/**
* @var LoggerInterface
*/
private $logger;
/**
* @var DataFetcher
*/
private $dataFetcher;
/**
* @var ResourceFactory
*/
private $resourceFactory;
/**
* @var MetaDataRepository
*/
private $metaDataRepository;
private readonly LoggerInterface $logger;
public function __construct(
LogManager $logManager,
DataFetcher $dataFetcher,
ResourceFactory $resourceFactory,
MetaDataRepository $metaDataRepository
private readonly DataFetcher $dataFetcher,
private readonly ResourceFactory $resourceFactory,
private readonly MetaDataRepository $metaDataRepository
) {
$this->logger = $logManager->getLogger(self::class);
$this->dataFetcher = $dataFetcher;
$this->resourceFactory = $resourceFactory;
$this->metaDataRepository = $metaDataRepository;
}
/**
@ -86,7 +66,7 @@ class FilesAssignment
continue;
}
$fileUrl = urldecode($mediaObject['url']);
$fileUrl = urldecode((string)$mediaObject['url']);
$orgFileNameSanitized = $importFolder->getStorage()->sanitizeFileName(basename($fileUrl));
$this->logger->info('File attached.', [$fileUrl, $orgFileNameSanitized]);
@ -124,7 +104,7 @@ class FilesAssignment
try {
$response = $this->dataFetcher->fetchImage($fileUrl);
} catch (Exception $e) {
} catch (Exception) {
$this->logger->error('Cannot load file.', [$fileUrl]);
return '';
}
@ -134,7 +114,7 @@ class FilesAssignment
return '';
}
$file = new \SplFileInfo($fileUrl);
$file = new SplFileInfo($fileUrl);
$temporaryFilename = GeneralUtility::tempnam($file->getBasename());
$writeResult = GeneralUtility::writeFile($temporaryFilename, $response->getBody()->__toString(), true);
if ($writeResult === false) {
@ -204,7 +184,6 @@ class FilesAssignment
];
return ((string)$mediaObject['rel']) === 'default'
&& in_array($mediaObject['type'], $allowedMimeTypes)
;
&& in_array($mediaObject['type'], $allowedMimeTypes);
}
}

View file

@ -1,21 +1,17 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Service\DestinationDataImportService;
use WerkraumMedia\Events\Domain\Model\Location;
use WerkraumMedia\Events\Domain\Repository\LocationRepository;
class LocationAssignment
final class LocationAssignment
{
/**
* @var LocationRepository
*/
private $repository;
public function __construct(
LocationRepository $repository
private readonly LocationRepository $repository
) {
$this->repository = $repository;
}
public function getLocation(array $event): ?Location
@ -28,8 +24,8 @@ class LocationAssignment
$event['district'] ?? '',
$event['country'] ?? '',
$event['phone'] ?? '',
$event['geo']['main']['latitude'] ?? '',
$event['geo']['main']['longitude'] ?? '',
(string)($event['geo']['main']['latitude'] ?? ''),
(string)($event['geo']['main']['longitude'] ?? ''),
-1
);

View file

@ -23,6 +23,8 @@ declare(strict_types=1);
namespace WerkraumMedia\Events\Service\DestinationDataImportService;
use Generator;
use PDO;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
use TYPO3\CMS\Core\DataHandling\SlugHelper;
@ -30,24 +32,12 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
use WerkraumMedia\Events\Service\DestinationDataImportService\Slugger\Registry;
use WerkraumMedia\Events\Service\DestinationDataImportService\Slugger\SluggerType;
class Slugger
final class Slugger
{
/**
* @var Registry
*/
private $registry;
/**
* @var ConnectionPool
*/
private $connectionPool;
public function __construct(
Registry $registry,
ConnectionPool $connectionPool
private readonly Registry $registry,
private readonly ConnectionPool $connectionPool
) {
$this->registry = $registry;
$this->connectionPool = $connectionPool;
}
public function update(string $tableName): void
@ -59,9 +49,9 @@ class Slugger
}
/**
* @return \Generator<array>
* @return Generator<array>
*/
private function getRecords(SluggerType $sluggerType): \Generator
private function getRecords(SluggerType $sluggerType): Generator
{
$tableName = $sluggerType->getSupportedTableName();
$slugColumn = $sluggerType->getSlugColumn();
@ -70,12 +60,13 @@ class Slugger
$statement = $queryBuilder->select('*')
->from($tableName)
->where(
$queryBuilder->expr()->orX(
$queryBuilder->expr()->eq($slugColumn, $queryBuilder->createNamedParameter('', \PDO::PARAM_STR)),
$queryBuilder->expr()->or(
$queryBuilder->expr()->eq($slugColumn, $queryBuilder->createNamedParameter('', PDO::PARAM_STR)),
$queryBuilder->expr()->isNull($slugColumn)
)
)
->execute();
->executeQuery()
;
while ($record = $statement->fetch()) {
if (is_array($record) === false) {
@ -97,11 +88,12 @@ class Slugger
->where(
$queryBuilder->expr()->eq(
'uid',
$queryBuilder->createNamedParameter($record['uid'], \PDO::PARAM_INT)
$queryBuilder->createNamedParameter($record['uid'], PDO::PARAM_INT)
)
)
->set($sluggerType->getSlugColumn(), $slug);
$queryBuilder->execute();
->set($sluggerType->getSlugColumn(), $slug)
;
$queryBuilder->executeStatement();
}
private function getSlugHelper(

View file

@ -23,24 +23,19 @@ declare(strict_types=1);
namespace WerkraumMedia\Events\Service\DestinationDataImportService\Slugger;
use DateTimeImmutable;
use TYPO3\CMS\Core\Database\ConnectionPool;
class Date implements SluggerType
final class Date implements SluggerType
{
/**
* @var ConnectionPool
*/
private $connectionPool;
public function __construct(
ConnectionPool $connectionPool
private readonly ConnectionPool $connectionPool
) {
$this->connectionPool = $connectionPool;
}
public function prepareRecordForSlugGeneration(array $record): array
{
$start = new \DateTimeImmutable('@' . $record['start']);
$start = new DateTimeImmutable('@' . $record['start']);
$record['event-title'] = $this->getEventTitle((int)$record['event']);
$record['start'] = $start->format('Y-m-d');
@ -64,7 +59,7 @@ class Date implements SluggerType
$qb->select('title');
$qb->from('tx_events_domain_model_event');
$qb->where($qb->expr()->eq('uid', $eventUid));
$title = $qb->execute()->fetchOne();
$title = $qb->executeQuery()->fetchOne();
if (is_string($title)) {
return $title;
}

View file

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace WerkraumMedia\Events\Service\DestinationDataImportService\Slugger;
class Event implements SluggerType
final class Event implements SluggerType
{
public function prepareRecordForSlugGeneration(array $record): array
{

View file

@ -23,17 +23,19 @@ declare(strict_types=1);
namespace WerkraumMedia\Events\Service\DestinationDataImportService\Slugger;
class Registry
use Exception;
final class Registry
{
/**
* @var SluggerType[]
*/
private $sluggers = [];
private array $sluggers = [];
public function get(string $tableName): SluggerType
{
if (!isset($this->sluggers[$tableName])) {
throw new \Exception(
throw new Exception(
sprintf(
'No slugger registered for table "%s", only for tables: "%s".',
$tableName,

View file

@ -1,16 +1,17 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Service\DestinationDataImportService;
use TYPO3\CMS\Core\Http\Uri;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManager;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager;
use WerkraumMedia\Events\Domain\Model\Import;
/**
* Factory to create URLs used during import of Destination Data.
*/
class UrlFactory
final class UrlFactory
{
/**
* @var array
@ -18,13 +19,12 @@ class UrlFactory
private $settings = [];
public function __construct(
ConfigurationManager $configurationManager
BackendConfigurationManager $configurationManager
) {
$this->settings = $configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS,
'Events',
'Pi1'
)['destinationData'] ?? [];
)['settings']['destinationData'] ?? [];
}
/**

View file

@ -1,54 +0,0 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2023 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program 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 2
* of the License, or (at your option) any later version.
*
* This program 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\Events\Testing;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Core\TypoScript\TemplateService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Hook\TypoScriptInstructionModifier as Typo3TypoScriptInstructionModifier;
use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\RequestBootstrap;
/**
* Wrap original code to check whether internal request exists.
* It does not exist during import.
*
* No PR upstream as this is probably an unusual use case.
* But we call frontend, import, frontend so have a mix.
*/
class TypoScriptInstructionModifier implements SingletonInterface
{
public function apply(array $parameters, TemplateService $service): void
{
$request = RequestBootstrap::getInternalRequest();
if ($request === null) {
return;
}
GeneralUtility::callUserFunction(
Typo3TypoScriptInstructionModifier::class . '->apply',
$parameters,
$service
);
}
}

View file

@ -26,20 +26,16 @@ namespace WerkraumMedia\Events\Updates;
use Generator;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Install\Attribute\UpgradeWizard;
use TYPO3\CMS\Install\Updates\UpgradeWizardInterface;
use WerkraumMedia\Events\Domain\Model\Location;
#[UpgradeWizard(MigrateDuplicateLocations::class)]
final class MigrateDuplicateLocations implements UpgradeWizardInterface
{
/**
* @var ConnectionPool
*/
private $connectionPool;
public function __construct(
ConnectionPool $connectionPool
private readonly ConnectionPool $connectionPool
) {
$this->connectionPool = $connectionPool;
}
public function getIdentifier(): string
@ -98,11 +94,6 @@ final class MigrateDuplicateLocations implements UpgradeWizardInterface
return [];
}
public static function register(): void
{
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'][self::class] = self::class;
}
/**
* @return Generator<array>
*/
@ -125,7 +116,7 @@ final class MigrateDuplicateLocations implements UpgradeWizardInterface
);
$queryBuilder->from('tx_events_domain_model_location');
$queryBuilder->orderBy('uid', 'asc');
$result = $queryBuilder->execute();
$result = $queryBuilder->executeQuery();
foreach ($result->fetchAllAssociative() as $location) {
yield $location;
@ -143,7 +134,7 @@ final class MigrateDuplicateLocations implements UpgradeWizardInterface
$queryBuilder->andWhere($queryBuilder->expr()->neq('uid', $queryBuilder->createNamedParameter($uid)));
$queryBuilder->setMaxResults(1);
$uid = $queryBuilder->execute()->fetchOne();
$uid = $queryBuilder->executeQuery()->fetchOne();
if (is_numeric($uid) === false) {
return 0;
}
@ -175,7 +166,7 @@ final class MigrateDuplicateLocations implements UpgradeWizardInterface
$queryBuilder->set('global_id', $location->getGlobalId());
$queryBuilder->set('latitude', $location->getLatitude());
$queryBuilder->set('longitude', $location->getLongitude());
$queryBuilder->execute();
$queryBuilder->executeStatement();
}
/**
@ -186,7 +177,7 @@ final class MigrateDuplicateLocations implements UpgradeWizardInterface
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('tx_events_domain_model_location');
$queryBuilder->delete('tx_events_domain_model_location');
$queryBuilder->where($queryBuilder->expr()->in('uid', $queryBuilder->createNamedParameter($uids, Connection::PARAM_INT_ARRAY)));
$queryBuilder->execute();
$queryBuilder->executeStatement();
}
private function updateRelations(array $migration): void
@ -198,7 +189,7 @@ final class MigrateDuplicateLocations implements UpgradeWizardInterface
$finalBuilder = clone $queryBuilder;
$finalBuilder->where($finalBuilder->expr()->eq('location', $finalBuilder->createNamedParameter($legacyLocationUid)));
$finalBuilder->set('location', $newLocationUid);
$finalBuilder->execute();
$finalBuilder->executeStatement();
}
}
}

View file

@ -23,43 +23,28 @@ declare(strict_types=1);
namespace WerkraumMedia\Events\Updates;
use Exception;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
use TYPO3\CMS\Core\DataHandling\DataHandler;
use TYPO3\CMS\Core\Log\Logger;
use TYPO3\CMS\Core\Log\LogManager;
use TYPO3\CMS\Install\Attribute\UpgradeWizard;
use TYPO3\CMS\Install\Updates\DatabaseUpdatedPrerequisite;
use TYPO3\CMS\Install\Updates\UpgradeWizardInterface;
#[UpgradeWizard(MigrateOldLocations::class)]
class MigrateOldLocations implements UpgradeWizardInterface
{
/**
* @var ConnectionPool
*/
private $connectionPool;
private readonly Logger $logger;
/**
* @var DataHandler
*/
private $dataHandler;
/**
* @var Logger
*/
private $logger;
/**
* @var array
*/
private $uidsForTranslation = [];
private array $uidsForTranslation = [];
public function __construct(
ConnectionPool $connectionPool,
DataHandler $dataHandler,
private readonly ConnectionPool $connectionPool,
private readonly DataHandler $dataHandler,
LogManager $logManager
) {
$this->connectionPool = $connectionPool;
$this->dataHandler = $dataHandler;
$this->logger = $logManager->getLogger(self::class);
}
@ -76,16 +61,12 @@ class MigrateOldLocations implements UpgradeWizardInterface
public function updateNecessary(): bool
{
return $this->hasOldColumns()
&& $this->getQueryBuilder()
->count('*')
->execute()
->fetchOne() > 0
;
&& $this->getQueryBuilder()->count('*')->executeQuery()->fetchOne() > 0;
}
public function executeUpdate(): bool
{
$result = $this->getQueryBuilder()->execute();
$result = $this->getQueryBuilder()->executeQuery()->iterateAssociative();
foreach ($result as $eventRecord) {
$this->logger->info('Updating event record.', ['record' => $eventRecord]);
$eventRecord['location'] = $this->getLocationUid($eventRecord);
@ -127,7 +108,7 @@ class MigrateOldLocations implements UpgradeWizardInterface
$qb->andWhere($qb->expr()->eq($column, $qb->createNamedParameter($event[$column])));
}
$uids = $qb->execute()->fetchAssociative();
$uids = $qb->executeQuery()->fetchAssociative();
if (is_bool($uids)) {
return 0;
}
@ -203,7 +184,7 @@ class MigrateOldLocations implements UpgradeWizardInterface
return $l10nParentUid;
}
throw new \Exception('Could not create location: ' . implode(', ', $dataHandler->errorLog), 1672916613);
throw new Exception('Could not create location: ' . implode(', ', $dataHandler->errorLog), 1672916613);
}
private function updateEvent(array $event): void
@ -255,7 +236,8 @@ class MigrateOldLocations implements UpgradeWizardInterface
->getConnectionForTable('tx_events_domain_model_event')
->getSchemaManager()
->createSchema()
->getTable('tx_events_domain_model_event');
->getTable('tx_events_domain_model_event')
;
foreach ($this->columnsToFetch() as $column) {
if ($schema->hasColumn($column) === false) {
@ -283,9 +265,4 @@ class MigrateOldLocations implements UpgradeWizardInterface
'longitude',
];
}
public static function register(): void
{
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'][self::class] = self::class;
}
}

View file

@ -2,8 +2,10 @@
declare(strict_types=1);
use WerkraumMedia\Events\Domain\Model\Category;
return [
\WerkraumMedia\Events\Domain\Model\Category::class => [
Category::class => [
'tableName' => 'sys_category',
],
];

View file

@ -48,3 +48,6 @@ services:
- name: event.listener
event: WerkraumMedia\Events\Events\Controller\DateListVariables
method: 'trackDates'
- name: event.listener
event: TYPO3\CMS\Frontend\Event\ModifyCacheLifetimeForPageEvent
method: 'modifyCacheLifetimeForPage'

View file

@ -1,11 +1,16 @@
<?php
declare(strict_types=1);
use TYPO3\CMS\Core\Utility\ArrayUtility;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
defined('TYPO3') or die();
(static function (string $extensionKey, string $tableName) {
$languagePath = 'LLL:EXT:events/Resources/Private/Language/locallang_db.xlf:' . $tableName;
\TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($GLOBALS['TCA'][$tableName], [
ArrayUtility::mergeRecursiveWithOverrule($GLOBALS['TCA'][$tableName], [
'ctrl' => [
'typeicon_classes' => [
'contains-events' => 'pages-module-events',
@ -13,13 +18,13 @@ defined('TYPO3') or die();
],
]);
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTcaSelectItem(
ExtensionManagementUtility::addTcaSelectItem(
$tableName,
'module',
[
0 => $languagePath . '.module.events',
1 => 'events',
2 => 'pages-module-events',
'label' => $languagePath . '.module.events',
'value' => 'events',
'icon' => 'pages-module-events',
]
);
})('events', 'pages');

View file

@ -1,7 +1,11 @@
<?php
declare(strict_types=1);
use TYPO3\CMS\Core\Utility\ArrayUtility;
(function (string $extKey, string $table) {
\TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($GLOBALS['TCA'][$table], [
ArrayUtility::mergeRecursiveWithOverrule($GLOBALS['TCA'][$table], [
'columns' => [
'sorting' => [
'config' => [

View file

@ -1,9 +1,13 @@
<?php
declare(strict_types=1);
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
defined('TYPO3') or die();
(static function (string $extensionKey, string $tableName) {
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile(
ExtensionManagementUtility::addStaticFile(
$extensionKey,
'Configuration/TypoScript',
'Events'

View file

@ -1,54 +1,59 @@
<?php
declare(strict_types=1);
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Extbase\Utility\ExtensionUtility;
(function (string $extKey, string $table) {
/* Search Plugin */
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
ExtensionUtility::registerPlugin(
'Events',
'DateSearch',
'Events: Date Search',
'EXT:events/Resources/Public/Icons/Extension.svg'
);
$GLOBALS['TCA'][$table]['types']['list']['subtypes_addlist']['events_datesearch'] = 'pi_flexform';
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
ExtensionManagementUtility::addPiFlexFormValue(
'events_datesearch',
'FILE:EXT:events/Configuration/FlexForms/DateSearch.xml'
);
/* Date List Plugin */
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
ExtensionUtility::registerPlugin(
'Events',
'DateList',
'Events: Date List',
'EXT:events/Resources/Public/Icons/Extension.svg'
);
$GLOBALS['TCA'][$table]['types']['list']['subtypes_addlist']['events_datelist'] = 'pi_flexform';
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
ExtensionManagementUtility::addPiFlexFormValue(
'events_datelist',
'FILE:EXT:events/Configuration/FlexForms/DateList.xml'
);
/* Date Show Plugin */
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
ExtensionUtility::registerPlugin(
'Events',
'DateShow',
'Events: Date Show',
'EXT:events/Resources/Public/Icons/Extension.svg'
);
$GLOBALS['TCA'][$table]['types']['list']['subtypes_addlist']['events_dateshow'] = 'pi_flexform';
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
ExtensionManagementUtility::addPiFlexFormValue(
'events_dateshow',
'FILE:EXT:events/Configuration/FlexForms/DateShow.xml'
);
/* Event Selected Plugin */
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
ExtensionUtility::registerPlugin(
'Events',
'Selected',
'Events: Show selected',
'EXT:events/Resources/Public/Icons/Extension.svg'
);
$GLOBALS['TCA'][$table]['types']['list']['subtypes_addlist']['events_selected'] = 'pi_flexform';
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
ExtensionManagementUtility::addPiFlexFormValue(
'events_selected',
'FILE:EXT:events/Configuration/FlexForms/Selected.xml'
);

View file

@ -1,29 +0,0 @@
<?php
(function (string $extKey, string $table) {
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::makeCategorizable(
$extKey,
$table,
'categories',
[
'label' => 'Categories',
'fieldConfiguration' => [
'minitems' => 0,
'multiple' => true,
],
]
);
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::makeCategorizable(
$extKey,
$table,
'features',
[
'label' => 'Features',
'fieldConfiguration' => [
'minitems' => 0,
'multiple' => true,
],
]
);
})('events', 'tx_events_domain_model_event');

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
return [
'ctrl' => [
'title' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_date.xlf:tx_events_domain_model_date',
@ -8,7 +10,6 @@ return [
'label_alt_force' => true,
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'cruser_id' => 'cruser_id',
'versioningWS' => true,
'languageField' => 'sys_language_uid',
'transOrigPointerField' => 'l10n_parent',
@ -29,19 +30,7 @@ return [
'sys_language_uid' => [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'special' => 'languages',
'items' => [
[
'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.allLanguages',
-1,
'flags-multiple',
],
],
'default' => 0,
],
'config' => ['type' => 'language'],
],
'l10n_parent' => [
'displayCond' => 'FIELD:sys_language_uid:>:0',
@ -51,7 +40,7 @@ return [
'renderType' => 'selectSingle',
'default' => 0,
'items' => [
['', 0],
['label' => '', 'value' => 0],
],
'foreign_table' => 'tx_events_domain_model_date',
'foreign_table_where' => 'AND {#tx_events_domain_model_date}.{#pid}=###CURRENT_PID### AND {#tx_events_domain_model_date}.{#sys_language_uid} IN (-1,0)',
@ -78,8 +67,7 @@ return [
'renderType' => 'checkboxToggle',
'items' => [
[
0 => '',
1 => '',
'label' => '',
'invertStateDisplay' => true,
],
],
@ -89,10 +77,8 @@ return [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.starttime',
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'eval' => 'datetime,int',
'default' => 0,
'type' => 'datetime',
'format' => 'datetime',
'behaviour' => [
'allowLanguageSynchronization' => true,
],
@ -102,13 +88,8 @@ return [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.endtime',
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'eval' => 'datetime,int',
'default' => 0,
'range' => [
'upper' => mktime(0, 0, 0, 1, 1, 2038),
],
'type' => 'datetime',
'format' => 'datetime',
'behaviour' => [
'allowLanguageSynchronization' => true,
],
@ -119,11 +100,9 @@ return [
'exclude' => true,
'label' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_date.xlf:tx_events_domain_model_date.start',
'config' => [
//'dbType' => 'datetime',
'type' => 'input',
'renderType' => 'inputDateTime',
'type' => 'datetime',
'format' => 'datetime',
'size' => 12,
'eval' => 'datetime',
'default' => null,
],
],
@ -131,11 +110,9 @@ return [
'exclude' => true,
'label' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_date.xlf:tx_events_domain_model_date.end',
'config' => [
//'dbType' => 'datetime',
'type' => 'input',
'renderType' => 'inputDateTime',
'type' => 'datetime',
'format' => 'datetime',
'size' => 12,
'eval' => 'datetime',
'default' => null,
],
],
@ -148,16 +125,16 @@ return [
'default' => 'no',
'items' => [
'0' => [
'0' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_date.xlf:tx_events_domain_model_date.canceled.options.no',
'1' => 'no',
'label' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_date.xlf:tx_events_domain_model_date.canceled.options.no',
'value' => 'no',
],
'1' => [
'0' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_date.xlf:tx_events_domain_model_date.canceled.options.canceled',
'1' => 'canceled',
'label' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_date.xlf:tx_events_domain_model_date.canceled.options.canceled',
'value' => 'canceled',
],
'2' => [
'0' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_date.xlf:tx_events_domain_model_date.canceled.options.postponed',
'1' => 'postponed',
'label' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_date.xlf:tx_events_domain_model_date.canceled.options.postponed',
'value' => 'postponed',
],
],
],
@ -174,8 +151,8 @@ return [
'default' => '0',
'items' => [
'0' => [
'0' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_date.xlf:tx_events_domain_model_date.postponed_date.0',
'1' => '0',
'label' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_date.xlf:tx_events_domain_model_date.postponed_date.0',
'value' => '0',
],
],
],
@ -185,18 +162,7 @@ return [
'label' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_date.xlf:tx_events_domain_model_date.canceled_link',
'displayCond' => 'FIELD:canceled:=:canceled',
'config' => [
'type' => 'input',
'softref' => 'typolink',
'renderType' => 'inputLink',
'max' => 1024,
'eval' => 'trim',
'fieldControl' => [
'linkPopup' => [
'options' => [
'title' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:header_link_formlabel',
],
],
],
'type' => 'link',
],
],
'slug' => [

View file

@ -1,7 +1,11 @@
<?php
declare(strict_types=1);
use TYPO3\CMS\Core\Resource\File;
$l10nPathGeneral = 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf';
$l10nPathLang = 'LLL:EXT:lang/locallang_core.xlf';
$l10nPathLang = 'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf';
$l10nPathFE = 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf';
$l10nPath = 'LLL:EXT:events/Resources/Private/Language/locallang_csh_event.xlf';
$l10nLocationPath = 'LLL:EXT:events/Resources/Private/Language/locallang_csh_location.xlf';
@ -12,7 +16,6 @@ return [
'label' => 'title',
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'cruser_id' => 'cruser_id',
'versioningWS' => true,
'languageField' => 'sys_language_uid',
'transOrigPointerField' => 'l10n_parent',
@ -78,19 +81,7 @@ return [
'sys_language_uid' => [
'exclude' => true,
'label' => $l10nPathGeneral . ':LGL.language',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'special' => 'languages',
'items' => [
[
$l10nPathGeneral . ':LGL.allLanguages',
-1,
'flags-multiple',
],
],
'default' => 0,
],
'config' => ['type' => 'language'],
],
'l10n_parent' => [
'displayCond' => 'FIELD:sys_language_uid:>:0',
@ -100,7 +91,7 @@ return [
'renderType' => 'selectSingle',
'default' => 0,
'items' => [
['', 0],
['label' => '', 'value' => 0],
],
'foreign_table' => 'tx_events_domain_model_event',
'foreign_table_where' => 'AND {#tx_events_domain_model_event}.{#pid}=###CURRENT_PID### AND {#tx_events_domain_model_event}.{#sys_language_uid} IN (-1,0)',
@ -127,8 +118,7 @@ return [
'renderType' => 'checkboxToggle',
'items' => [
[
0 => '',
1 => '',
'label' => '',
'invertStateDisplay' => true,
],
],
@ -138,10 +128,8 @@ return [
'exclude' => true,
'label' => $l10nPathGeneral . ':LGL.starttime',
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'eval' => 'datetime,int',
'default' => 0,
'type' => 'datetime',
'format' => 'datetime',
'behaviour' => [
'allowLanguageSynchronization' => true,
],
@ -151,13 +139,8 @@ return [
'exclude' => true,
'label' => $l10nPathGeneral . ':LGL.endtime',
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'eval' => 'datetime,int',
'default' => 0,
'range' => [
'upper' => mktime(0, 0, 0, 1, 1, 2038),
],
'type' => 'datetime',
'format' => 'datetime',
'behaviour' => [
'allowLanguageSynchronization' => true,
],
@ -205,9 +188,7 @@ return [
'exclude' => true,
'label' => $l10nPath . ':tx_events_domain_model_event.source_url',
'config' => [
'type' => 'input',
'renderType' => 'inputLink',
'softref' => 'typolink',
'type' => 'link',
'readOnly' => true,
],
],
@ -235,8 +216,7 @@ return [
'renderType' => 'checkboxToggle',
'items' => [
[
0 => '',
1 => '',
'label' => '',
'invertStateDisplay' => false,
],
],
@ -293,12 +273,8 @@ return [
'exclude' => true,
'label' => $l10nPath . ':tx_events_domain_model_event.ticket',
'config' => [
'type' => 'input',
'renderType' => 'inputLink',
'eval' => 'trim',
'max' => 1024,
'type' => 'link',
'size' => 50,
'softref' => 'typolink',
],
],
'facebook' => [
@ -331,57 +307,27 @@ return [
'images' => [
'exclude' => true,
'label' => $l10nPath . ':tx_events_domain_model_event.images',
'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig(
'images',
[
'appearance' => [
'createNewRelationLinkTitle' => $l10nPathFE . ':images.addFileReference',
'showPossibleLocalizationRecords' => true,
'showRemovedLocalizationRecords' => true,
'showAllLocalizationLink' => true,
'showSynchronizationLink' => true,
],
'foreign_match_fields' => [
'fieldname' => 'images',
'tablenames' => 'tx_events_domain_model_event',
'table_local' => 'sys_file',
],
'foreign_types' => [
'config' => [
'type' => 'file',
'maxitems' => 8,
'allowed' => 'common-image-types',
// custom configuration for displaying fields in the overlay/reference table
// to use the imageoverlayPalette instead of the basicoverlayPalette
'overrideChildTca' => [
'types' => [
'0' => [
'showitem' => '
--palette--;' . $l10nPathFE . ':sys_file_reference.imageoverlayPalette;imageoverlayPalette,
--palette--;;filePalette',
--palette--;;imageoverlayPalette,
--palette--;;filePalette',
],
\TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => [
File::FILETYPE_IMAGE => [
'showitem' => '
--palette--;' . $l10nPathFE . ':sys_file_reference.imageoverlayPalette;imageoverlayPalette,
--palette--;;filePalette',
],
\TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [
'showitem' => '
--palette--;' . $l10nPathFE . ':sys_file_reference.imageoverlayPalette;imageoverlayPalette,
--palette--;;filePalette',
],
\TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => [
'showitem' => '
--palette--;' . $l10nPathFE . ':sys_file_reference.imageoverlayPalette;imageoverlayPalette,
--palette--;;filePalette',
],
\TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => [
'showitem' => '
--palette--;' . $l10nPathFE . ':sys_file_reference.imageoverlayPalette;imageoverlayPalette,
--palette--;;filePalette',
],
\TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => [
'showitem' => '
--palette--;' . $l10nPathFE . ':sys_file_reference.imageoverlayPalette;imageoverlayPalette,
--palette--;;filePalette',
--palette--;;imageoverlayPalette,
--palette--;;filePalette',
],
],
'maxitems' => 8,
],
$GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']
),
],
],
'pages' => [
@ -389,16 +335,27 @@ return [
'label' => $l10nPath . ':tx_events_domain_model_event.pages',
'config' => [
'type' => 'group',
'internal_type' => 'db',
'allowed' => 'pages',
],
],
'categories' => [
'exclude' => true,
'label' => 'Categories',
'config' => [
'type' => 'category',
'minitems' => 0,
'multiple' => true,
],
],
'features' => [
'exclude' => true,
'label' => 'Features',
'config' => [
'type' => 'category',
'minitems' => 0,
'multiple' => true,
],
],
'dates' => [
@ -424,7 +381,6 @@ return [
],
'levelLinksPosition' => 'top',
'showPossibleLocalizationRecords' => false,
'showRemovedLocalizationRecords' => false,
'showSynchronizationLink' => false,
'showAllLocalizationLink' => false,
],
@ -475,7 +431,6 @@ return [
'label' => $l10nPath . ':tx_events_domain_model_event.references_events',
'config' => [
'type' => 'group',
'internal_type' => 'db',
'allowed' => 'tx_events_domain_model_event',
'suggestOptions' => [
'tx_events_domain_model_event' => [
@ -490,7 +445,6 @@ return [
'label' => $l10nPath . ':tx_events_domain_model_event.partner',
'config' => [
'type' => 'group',
'internal_type' => 'db',
'allowed' => 'tx_events_domain_model_partner',
'fieldControl' => [
'addRecord' => [

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
return [
'ctrl' => [
'title' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_import.xlf:tx_events_domain_model_import',
@ -8,7 +10,6 @@ return [
'label_alt_force' => true,
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'cruser_id' => 'cruser_id',
'delete' => 'deleted',
'enablecolumns' => [
'disabled' => 'hidden',
@ -48,8 +49,7 @@ return [
'renderType' => 'checkboxToggle',
'items' => [
[
0 => '',
1 => '',
'label' => '',
'invertStateDisplay' => true,
],
],
@ -72,7 +72,6 @@ return [
'description' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_import.xlf:tx_events_domain_model_import.storage_pid.description',
'config' => [
'type' => 'group',
'internal_type' => 'db',
'allowed' => 'pages',
'size' => 1,
'maxitems' => 1,
@ -84,7 +83,6 @@ return [
'label' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_import.xlf:tx_events_domain_model_import.region',
'config' => [
'type' => 'group',
'internal_type' => 'db',
'allowed' => 'tx_events_domain_model_region',
'size' => 1,
'maxitems' => 1,
@ -97,7 +95,6 @@ return [
'description' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_import.xlf:tx_events_domain_model_import.categories_pid.description',
'config' => [
'type' => 'group',
'internal_type' => 'db',
'allowed' => 'pages',
'size' => 1,
'maxitems' => 1,
@ -110,7 +107,6 @@ return [
'description' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_import.xlf:tx_events_domain_model_import.category_parent.description',
'config' => [
'type' => 'group',
'internal_type' => 'db',
'allowed' => 'sys_category',
'size' => 1,
'maxitems' => 1,
@ -123,7 +119,6 @@ return [
'description' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_import.xlf:tx_events_domain_model_import.features_pid.description',
'config' => [
'type' => 'group',
'internal_type' => 'db',
'allowed' => 'pages',
'size' => 1,
'maxitems' => 1,
@ -136,7 +131,6 @@ return [
'description' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_import.xlf:tx_events_domain_model_import.features_parent.description',
'config' => [
'type' => 'group',
'internal_type' => 'db',
'allowed' => 'sys_category',
'size' => 1,
'maxitems' => 1,
@ -148,8 +142,7 @@ return [
'label' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_import.xlf:tx_events_domain_model_import.files_folder',
'description' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_import.xlf:tx_events_domain_model_import.files_folder.description',
'config' => [
'type' => 'group',
'internal_type' => 'folder',
'type' => 'folder',
'size' => 1,
'maxitems' => 1,
'minitems' => 1,

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
$l10nPathGeneral = 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf';
$l10nPath = 'LLL:EXT:events/Resources/Private/Language/locallang_csh_location.xlf';
@ -9,7 +11,6 @@ return [
'label' => 'name',
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'cruser_id' => 'cruser_id',
'versioningWS' => true,
'languageField' => 'sys_language_uid',
'transOrigPointerField' => 'l10n_parent',
@ -50,19 +51,7 @@ return [
'sys_language_uid' => [
'exclude' => true,
'label' => $l10nPathGeneral . ':LGL.language',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'special' => 'languages',
'items' => [
[
$l10nPathGeneral . ':LGL.allLanguages',
-1,
'flags-multiple',
],
],
'default' => 0,
],
'config' => ['type' => 'language'],
],
'l10n_parent' => [
'displayCond' => 'FIELD:sys_language_uid:>:0',
@ -72,7 +61,7 @@ return [
'renderType' => 'selectSingle',
'default' => 0,
'items' => [
['', 0],
['label' => '', 'value' => 0],
],
'foreign_table' => 'tx_events_domain_model_location',
'foreign_table_where' => 'AND {#tx_events_domain_model_location}.{#pid}=###CURRENT_PID### AND {#tx_events_domain_model_location}.{#sys_language_uid} IN (-1,0)',
@ -99,8 +88,7 @@ return [
'renderType' => 'checkboxToggle',
'items' => [
[
0 => '',
1 => '',
'label' => '',
'invertStateDisplay' => true,
],
],
@ -110,10 +98,8 @@ return [
'exclude' => true,
'label' => $l10nPathGeneral . ':LGL.starttime',
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'eval' => 'datetime,int',
'default' => 0,
'type' => 'datetime',
'format' => 'datetime',
'behaviour' => [
'allowLanguageSynchronization' => true,
],
@ -123,13 +109,8 @@ return [
'exclude' => true,
'label' => $l10nPathGeneral . ':LGL.endtime',
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'eval' => 'datetime,int',
'default' => 0,
'range' => [
'upper' => mktime(0, 0, 0, 1, 1, 2038),
],
'type' => 'datetime',
'format' => 'datetime',
'behaviour' => [
'allowLanguageSynchronization' => true,
],

View file

@ -1,12 +1,13 @@
<?php
declare(strict_types=1);
return [
'ctrl' => [
'title' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_organizer.xlf:tx_events_domain_model_organizer',
'label' => 'name',
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'cruser_id' => 'cruser_id',
'versioningWS' => true,
'languageField' => 'sys_language_uid',
'transOrigPointerField' => 'l10n_parent',
@ -27,19 +28,7 @@ return [
'sys_language_uid' => [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'special' => 'languages',
'items' => [
[
'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.allLanguages',
-1,
'flags-multiple',
],
],
'default' => 0,
],
'config' => ['type' => 'language'],
],
'l10n_parent' => [
'displayCond' => 'FIELD:sys_language_uid:>:0',
@ -49,7 +38,7 @@ return [
'renderType' => 'selectSingle',
'default' => 0,
'items' => [
['', 0],
['label' => '', 'value' => 0],
],
'foreign_table' => 'tx_events_domain_model_organizer',
'foreign_table_where' => 'AND {#tx_events_domain_model_organizer}.{#pid}=###CURRENT_PID### AND {#tx_events_domain_model_organizer}.{#sys_language_uid} IN (-1,0)',
@ -76,8 +65,7 @@ return [
'renderType' => 'checkboxToggle',
'items' => [
[
0 => '',
1 => '',
'label' => '',
'invertStateDisplay' => true,
],
],
@ -87,10 +75,8 @@ return [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.starttime',
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'eval' => 'datetime,int',
'default' => 0,
'type' => 'datetime',
'format' => 'datetime',
'behaviour' => [
'allowLanguageSynchronization' => true,
],
@ -100,13 +86,8 @@ return [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.endtime',
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'eval' => 'datetime,int',
'default' => 0,
'range' => [
'upper' => mktime(0, 0, 0, 1, 1, 2038),
],
'type' => 'datetime',
'format' => 'datetime',
'behaviour' => [
'allowLanguageSynchronization' => true,
],

View file

@ -1,12 +1,15 @@
<?php
declare(strict_types=1);
use TYPO3\CMS\Core\Resource\File;
return [
'ctrl' => [
'title' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_partner.xlf:tx_events_domain_model_partner',
'label' => 'title',
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'cruser_id' => 'cruser_id',
'versioningWS' => true,
'languageField' => 'sys_language_uid',
'transOrigPointerField' => 'l10n_parent',
@ -25,19 +28,7 @@ return [
'sys_language_uid' => [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'special' => 'languages',
'items' => [
[
'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.allLanguages',
-1,
'flags-multiple',
],
],
'default' => 0,
],
'config' => ['type' => 'language'],
],
'l10n_parent' => [
'displayCond' => 'FIELD:sys_language_uid:>:0',
@ -47,7 +38,7 @@ return [
'renderType' => 'selectSingle',
'default' => 0,
'items' => [
['', 0],
['label' => '', 'value' => 0],
],
'foreign_table' => 'tx_events_domain_model_partner',
'foreign_table_where' => 'AND {#tx_events_domain_model_partner}.{#pid}=###CURRENT_PID### AND {#tx_events_domain_model_partner}.{#sys_language_uid} IN (-1,0)',
@ -74,8 +65,7 @@ return [
'renderType' => 'checkboxToggle',
'items' => [
[
0 => '',
1 => '',
'label' => '',
'invertStateDisplay' => true,
],
],
@ -95,21 +85,15 @@ return [
'exclude' => true,
'label' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_partner.xlf:tx_events_domain_model_partner.link',
'config' => [
'type' => 'input',
'renderType' => 'inputLink',
'eval' => 'trim',
'max' => 1024,
'size' => 50,
'softref' => 'typolink',
'type' => 'link',
],
],
'images' => [
'exclude' => true,
'label' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_partner.xlf:tx_events_domain_model_partner.images',
'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig('images', [
'appearance' => [
'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference',
],
'config' => [
'type' => 'file',
'allowed' => 'common-image-types',
// custom configuration for displaying fields in the overlay/reference table
// to use the imageoverlayPalette instead of the basicoverlayPalette
'overrideChildTca' => [
@ -119,14 +103,14 @@ return [
--palette--;;imageoverlayPalette,
--palette--;;filePalette',
],
\TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [
File::FILETYPE_IMAGE => [
'showitem' => '
--palette--;;imageoverlayPalette,
--palette--;;filePalette',
],
],
],
], $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']),
],
],
],
];

View file

@ -1,12 +1,13 @@
<?php
declare(strict_types=1);
return [
'ctrl' => [
'title' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_region.xlf:tx_events_domain_model_region',
'label' => 'title',
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'cruser_id' => 'cruser_id',
'versioningWS' => true,
'languageField' => 'sys_language_uid',
'transOrigPointerField' => 'l10n_parent',
@ -27,19 +28,7 @@ return [
'sys_language_uid' => [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'special' => 'languages',
'items' => [
[
'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.allLanguages',
-1,
'flags-multiple',
],
],
'default' => 0,
],
'config' => ['type' => 'language'],
],
'l10n_parent' => [
'displayCond' => 'FIELD:sys_language_uid:>:0',
@ -49,7 +38,7 @@ return [
'renderType' => 'selectSingle',
'default' => 0,
'items' => [
['', 0],
['label' => '', 'value' => 0],
],
'foreign_table' => 'tx_events_domain_model_region',
'foreign_table_where' => 'AND {#tx_events_domain_model_region}.{#pid}=###CURRENT_PID### AND {#tx_events_domain_model_region}.{#sys_language_uid} IN (-1,0)',
@ -76,8 +65,7 @@ return [
'renderType' => 'checkboxToggle',
'items' => [
[
0 => '',
1 => '',
'label' => '',
'invertStateDisplay' => true,
],
],
@ -87,10 +75,8 @@ return [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.starttime',
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'eval' => 'datetime,int',
'default' => 0,
'type' => 'datetime',
'format' => 'datetime',
'behaviour' => [
'allowLanguageSynchronization' => true,
],
@ -100,13 +86,8 @@ return [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.endtime',
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'eval' => 'datetime,int',
'default' => 0,
'range' => [
'upper' => mktime(0, 0, 0, 1, 1, 2038),
],
'type' => 'datetime',
'format' => 'datetime',
'behaviour' => [
'allowLanguageSynchronization' => true,
],

View file

@ -24,10 +24,6 @@ plugin.tx_events {
recursive = 1
}
features {
skipDefaultArguments = 1
}
mvc {
callDefaultActionIfActionCantBeResolved = 1
}

View file

@ -4,6 +4,11 @@
Breaking
--------
* Drop support of TYPO3 and PHP versions.
We drop support for any TYPO3 version below 12.
We drop support for PHP versions not supported by TYPO3 v12.
That eases the maintenance of the extension.
* Change of vendor/namespace.
The vendor was renamed from `wrm` to `werkraummedia`.
And the namespace vendor was renamed from `Wrm` to `WerkraumMedia`.
@ -11,10 +16,15 @@ Breaking
That way all references to PHP classes as well as the package name itself need to
be adjusted.
* No longer allow records on standard pages.
Please use TCA Overrides in case you need this none default TYPO3 behaviour.
Features
--------
Nothing
* Support TYPO3 v12.
* Support PHP 8.1, 8.2, 8.3.
Fixes
-----

View file

@ -42,7 +42,6 @@ Table of Contents
Commands
Settings
Changelog
Maintenance
.. toctree::
:hidden:

View file

@ -1,16 +0,0 @@
.. _maintenance:
Maintenance
===========
List of changes that need to be done for maintenance reasons.
E.g. changes once we drop a certain TYPO3 version.
We might have new code backported for compatibility in older TYPO3 versions.
Those changes are documented so we know what to do once we drop an older version.
.. toctree::
:glob:
:reversed:
Maintenance/TYPO3/*

View file

@ -1,17 +0,0 @@
TYPO3 V10
=========
Changes that should happen once we drop TYPO3 v10.
Remove fetching cached page stage from body from tests
------------------------------------------------------
We have different assertions based on TYPO3 version, due to how TYPO3 exposes the info.
We can remove the condition with its content once we drop v10.
Remove condition for page not found handling
--------------------------------------------
The :php:`AbstractController->trigger404()` method has a condition to handle 404 differently for TYPO3 v10.
The condition can be removed.

View file

@ -1,12 +0,0 @@
TYPO3 V11
=========
Changes that should happen once we drop TYPO3 v11.
Remove ``SlidingWindowPagination`` backport.
--------------------------------------------
We backported https://docs.typo3.org/c/typo3/cms-core/main/en-us/Changelog/12.0/Feature-94625-IntroduceSlidingWindowPagination.html.
That allowed us to use the new Code compatible with v12 onwards.
We should remove the file ``Classes/Backports/V12/Pagination/SlidingWindowPagination.php`` and switch to TYPO3 native class within ``WerkraumMedia\Events\Pagination\Factory``.

View file

@ -0,0 +1,30 @@
Issue: https://github.com/TYPO3/testing-framework/issues/517
PR: https://github.com/TYPO3/testing-framework/pull/518
diff --git a/Classes/Core/Functional/Framework/FrameworkState.php b/Classes/Core/Functional/Framework/FrameworkState.php
index 93716fc..f900539 100644
--- a/Classes/Core/Functional/Framework/FrameworkState.php
+++ b/Classes/Core/Functional/Framework/FrameworkState.php
@@ -50,6 +50,7 @@ class FrameworkState
// different. And code that runs after that within the test scope may fail (eg. the referenceIndex check in tearDown() that
// relies on TCA). So we back up TCA for now before executing frontend tests.
$state['globals-tca'] = $GLOBALS['TCA'];
+ $state['request'] = $GLOBALS['TYPO3_REQUEST'] ?? null;
// Can be dropped when GeneralUtility::getIndpEnv() is abandoned
$generalUtilityReflection = new \ReflectionClass(GeneralUtility::class);
@@ -67,6 +68,7 @@ class FrameworkState
public static function reset()
{
unset($GLOBALS['BE_USER']);
+ unset($GLOBALS['TYPO3_REQUEST']);
$generalUtilityReflection = new \ReflectionClass(GeneralUtility::class);
$generalUtilityIndpEnvCache = $generalUtilityReflection->getProperty('indpEnvCache');
@@ -91,6 +93,7 @@ class FrameworkState
}
$GLOBALS['TCA'] = $state['globals-tca'];
+ $GLOBALS['TYPO3_REQUEST'] = $state['request'];
$generalUtilityReflection = new \ReflectionClass(GeneralUtility::class);
$generalUtilityIndpEnvCache = $generalUtilityReflection->getProperty('indpEnvCache');

View file

@ -0,0 +1,18 @@
Use "same" value for tstamp and crdate.
Otherwise TYPO3 will have different cache identifier if multiple requests with same instruction are given.
diff --git a/Resources/Core/Functional/Extensions/json_response/Classes/EventListener/AddTypoScriptFromInternalRequest.php b/Resources/Core/Functional/Extensions/json_response/Classes/EventListener/AddTypoScriptFromInternalRequest.php
index 111a997..504a899 100644
--- a/Resources/Core/Functional/Extensions/json_response/Classes/EventListener/AddTypoScriptFromInternalRequest.php
+++ b/Resources/Core/Functional/Extensions/json_response/Classes/EventListener/AddTypoScriptFromInternalRequest.php
@@ -49,8 +49,8 @@ final class AddTypoScriptFromInternalRequest
$newTemplateRow = [
'uid' => PHP_INT_MAX,
'pid' => PHP_INT_MAX,
- 'tstamp' => time(),
- 'crdate' => time(),
+ 'tstamp' => (new \DateTimeImmutable('midnight'))->format('U'),
+ 'crdate' => (new \DateTimeImmutable('midnight'))->format('U'),
'deleted' => 0,
'starttime' => 0,
'endtime' => 0,

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Tests;
use GuzzleHttp\Client;

View file

@ -30,16 +30,16 @@ use Psr\Http\Client\ClientInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\DependencyInjection\Container;
use TypeError;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Context\DateTimeAspect;
use TYPO3\CMS\Core\Localization\LanguageServiceFactory;
use TYPO3\CMS\Core\TypoScript\TemplateService;
use TYPO3\CMS\Core\Utility\ArrayUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Internal\TypoScriptInstruction;
use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
use UnexpectedValueException;
use WerkraumMedia\Events\Command\ImportDestinationDataViaConfigruationCommand;
use WerkraumMedia\Events\Testing\TypoScriptInstructionModifier;
use WerkraumMedia\Events\Tests\ClientFactory;
abstract class AbstractFunctionalTestCase extends FunctionalTestCase
@ -55,18 +55,21 @@ abstract class AbstractFunctionalTestCase extends FunctionalTestCase
protected function setUp(): void
{
$this->coreExtensionsToLoad = array_merge($this->coreExtensionsToLoad, [
$this->coreExtensionsToLoad = [
...$this->coreExtensionsToLoad,
'filelist',
'fluid_styled_content',
]);
];
$this->testExtensionsToLoad = array_merge($this->testExtensionsToLoad, [
$this->testExtensionsToLoad = [
...$this->testExtensionsToLoad,
'typo3conf/ext/events',
]);
];
$this->pathsToProvideInTestInstance = array_merge($this->pathsToProvideInTestInstance, [
$this->pathsToLinkInTestInstance = [
...$this->pathsToLinkInTestInstance,
'typo3conf/ext/events/Tests/Functional/Frontend/Fixtures/Sites/' => 'typo3conf/sites',
]);
];
ArrayUtility::mergeRecursiveWithOverrule($this->configurationToUseInTestInstance, [
'FE' => [
@ -80,22 +83,16 @@ abstract class AbstractFunctionalTestCase extends FunctionalTestCase
'processor_path_lzw' => '/usr/bin/',
'processor' => 'ImageMagick',
],
'SC_OPTIONS' => [
'Core/TypoScript/TemplateService' => [
'runThroughTemplatesPostProcessing' => [
'FunctionalTest' => TypoScriptInstructionModifier::class . '->apply',
],
],
],
]);
parent::setUp();
$this->setUpBackendUserFromFixture(1);
$this->importPHPDataSet(__DIR__ . '/Fixtures/BeUsers.php');
$this->setUpBackendUser(1);
$languageServiceFactory = $this->getContainer()->get(LanguageServiceFactory::class);
if (!$languageServiceFactory instanceof LanguageServiceFactory) {
throw new \UnexpectedValueException('Did not retrieve LanguageServiceFactory.', 1637847250);
throw new UnexpectedValueException('Did not retrieve LanguageServiceFactory.', 1637847250);
}
$GLOBALS['LANG'] = $languageServiceFactory->create('default');
@ -114,7 +111,7 @@ abstract class AbstractFunctionalTestCase extends FunctionalTestCase
protected function getTypoScriptInstruction(): TypoScriptInstruction
{
return new TypoScriptInstruction(TemplateService::class);
return new TypoScriptInstruction();
}
protected function setUpConfiguration(
@ -152,7 +149,7 @@ abstract class AbstractFunctionalTestCase extends FunctionalTestCase
array $argumentsAndOptions = ['configurationUid' => '1'],
string $command = ImportDestinationDataViaConfigruationCommand::class
): CommandTester {
$subject = $this->getContainer()->get($command);
$subject = $this->get($command);
self::assertInstanceOf(Command::class, $subject);
$tester = new CommandTester($subject);
@ -192,7 +189,7 @@ abstract class AbstractFunctionalTestCase extends FunctionalTestCase
{
$context = $this->getContainer()->get(Context::class);
if (!$context instanceof Context) {
throw new \TypeError('Retrieved context was of unexpected type.', 1638182021);
throw new TypeError('Retrieved context was of unexpected type.', 1638182021);
}
$aspect = new DateTimeAspect($dateTime);

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
return [
'pages' => [
[
@ -45,7 +47,6 @@ return [
'pid' => '0',
'tstamp' => '1423209858',
'crdate' => '1370878372',
'cruser_id' => '0',
'deleted' => '0',
'name' => 'fileadmin/ (auto-created)',
'description' => 'This is the local fileadmin/ directory. This storage mount has been created automatically by TYPO3.',
@ -126,7 +127,6 @@ return [
'pid' => '0',
'tstamp' => '1371467047',
'crdate' => '1371467047',
'cruser_id' => '1',
'file' => '1',
],
[
@ -134,7 +134,6 @@ return [
'pid' => '0',
'tstamp' => '1371467047',
'crdate' => '1371467047',
'cruser_id' => '1',
'file' => '2',
],
],
@ -144,7 +143,6 @@ return [
'pid' => '2',
'tstamp' => '1373537480',
'crdate' => '1371484347',
'cruser_id' => '1',
'deleted' => '0',
'hidden' => '0',
'sys_language_uid' => '0',
@ -153,14 +151,12 @@ return [
'tablenames' => 'tx_events_domain_model_event',
'fieldname' => 'images',
'sorting_foreign' => '1',
'table_local' => 'sys_file',
],
[
'uid' => '2',
'pid' => '2',
'tstamp' => '1373537480',
'crdate' => '1371484347',
'cruser_id' => '1',
'deleted' => '0',
'hidden' => '0',
'sys_language_uid' => '0',
@ -169,7 +165,6 @@ return [
'tablenames' => 'tx_events_domain_model_partner',
'fieldname' => 'images',
'sorting_foreign' => '1',
'table_local' => 'sys_file',
],
],
'tx_events_domain_model_region' => [

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
return [
'pages' => [
[
@ -51,7 +53,6 @@ return [
'pid' => '0',
'tstamp' => '1423209858',
'crdate' => '1370878372',
'cruser_id' => '0',
'deleted' => '0',
'name' => 'fileadmin/ (auto-created)',
'description' => 'This is the local fileadmin/ directory. This storage mount has been created automatically by TYPO3.',
@ -212,7 +213,6 @@ return [
'pid' => '0',
'tstamp' => '1371467047',
'crdate' => '1371467047',
'cruser_id' => '1',
'file' => '1',
],
[
@ -220,7 +220,6 @@ return [
'pid' => '0',
'tstamp' => '1371467047',
'crdate' => '1371467047',
'cruser_id' => '1',
'file' => '2',
],
[
@ -228,7 +227,6 @@ return [
'pid' => '0',
'tstamp' => '1371467047',
'crdate' => '1371467047',
'cruser_id' => '1',
'file' => '3',
],
[
@ -236,7 +234,6 @@ return [
'pid' => '0',
'tstamp' => '1371467047',
'crdate' => '1371467047',
'cruser_id' => '1',
'file' => '4',
],
[
@ -244,7 +241,6 @@ return [
'pid' => '0',
'tstamp' => '1371467047',
'crdate' => '1371467047',
'cruser_id' => '1',
'file' => '5',
],
[
@ -252,7 +248,6 @@ return [
'pid' => '0',
'tstamp' => '1371467047',
'crdate' => '1371467047',
'cruser_id' => '1',
'file' => '6',
],
],
@ -262,7 +257,6 @@ return [
'pid' => '2',
'tstamp' => '1373537480',
'crdate' => '1371484347',
'cruser_id' => '1',
'deleted' => '0',
'hidden' => '0',
'sys_language_uid' => '0',
@ -271,14 +265,12 @@ return [
'tablenames' => 'tx_events_domain_model_event',
'fieldname' => 'images',
'sorting_foreign' => '1',
'table_local' => 'sys_file',
],
[
'uid' => '2',
'pid' => '2',
'tstamp' => '1373537480',
'crdate' => '1371484347',
'cruser_id' => '1',
'deleted' => '0',
'hidden' => '0',
'sys_language_uid' => '0',
@ -287,14 +279,12 @@ return [
'tablenames' => 'tx_events_domain_model_partner',
'fieldname' => 'images',
'sorting_foreign' => '1',
'table_local' => 'sys_file',
],
[
'uid' => '3',
'pid' => '2',
'tstamp' => '1373537480',
'crdate' => '1371484347',
'cruser_id' => '1',
'deleted' => '0',
'hidden' => '0',
'sys_language_uid' => '0',
@ -303,14 +293,12 @@ return [
'tablenames' => 'tx_events_domain_model_event',
'fieldname' => 'images',
'sorting_foreign' => '1',
'table_local' => 'sys_file',
],
[
'uid' => '4',
'pid' => '2',
'tstamp' => '1373537480',
'crdate' => '1371484347',
'cruser_id' => '1',
'deleted' => '1',
'hidden' => '0',
'sys_language_uid' => '0',
@ -319,14 +307,12 @@ return [
'tablenames' => 'tt_content',
'fieldname' => 'images',
'sorting_foreign' => '1',
'table_local' => 'sys_file',
],
[
'uid' => '5',
'pid' => '2',
'tstamp' => '1373537480',
'crdate' => '1371484347',
'cruser_id' => '1',
'deleted' => '0',
'hidden' => '0',
'sys_language_uid' => '0',
@ -335,14 +321,12 @@ return [
'tablenames' => 'tx_events_domain_model_event',
'fieldname' => 'images',
'sorting_foreign' => '1',
'table_local' => 'sys_file',
],
[
'uid' => '6',
'pid' => '2',
'tstamp' => '1373537480',
'crdate' => '1371484347',
'cruser_id' => '1',
'deleted' => '0',
'hidden' => '0',
'sys_language_uid' => '0',
@ -351,14 +335,12 @@ return [
'tablenames' => '',
'fieldname' => '',
'sorting_foreign' => '0',
'table_local' => 'sys_file',
],
[
'uid' => '7',
'pid' => '0',
'tstamp' => '1373537480',
'crdate' => '1371484347',
'cruser_id' => '1',
'deleted' => '0',
'hidden' => '0',
'sys_language_uid' => '0',
@ -367,14 +349,12 @@ return [
'tablenames' => 'pages',
'fieldname' => 'media',
'sorting_foreign' => '0',
'table_local' => 'sys_file',
],
[
'uid' => '8',
'pid' => '0',
'tstamp' => '1373537480',
'crdate' => '1371484347',
'cruser_id' => '1',
'deleted' => '0',
'hidden' => '0',
'sys_language_uid' => '0',
@ -383,7 +363,6 @@ return [
'tablenames' => 'tx_events_domain_model_event',
'fieldname' => 'images',
'sorting_foreign' => '2',
'table_local' => 'sys_file',
],
],
'tx_events_domain_model_region' => [

View file

@ -1,16 +1,18 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Tests\Functional\Cleanup;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\TestDox;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Tester\CommandTester;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use WerkraumMedia\Events\Command\RemoveAllCommand;
use WerkraumMedia\Events\Tests\Functional\AbstractFunctionalTestCase;
/**
* @testdox Cleanup RemoveAll
*/
#[TestDox('Cleanup RemoveAll')]
class RemoveAllTest extends AbstractFunctionalTestCase
{
protected function setUp(): void
@ -22,9 +24,7 @@ class RemoveAllTest extends AbstractFunctionalTestCase
parent::setUp();
}
/**
* @test
*/
#[Test]
public function removesAllData(): void
{
$this->importPHPDataSet(__DIR__ . '/Fixtures/RemoveAllTestDatabase.php');

View file

@ -1,16 +1,18 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Tests\Functional\Cleanup;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\TestDox;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Tester\CommandTester;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use WerkraumMedia\Events\Command\RemovePastCommand;
use WerkraumMedia\Events\Tests\Functional\AbstractFunctionalTestCase;
/**
* @testdox Cleanup RemovePast
*/
#[TestDox('Cleanup RemovePast')]
class RemovePastTest extends AbstractFunctionalTestCase
{
protected function setUp(): void
@ -22,9 +24,7 @@ class RemovePastTest extends AbstractFunctionalTestCase
parent::setUp();
}
/**
* @test
*/
#[Test]
public function removesPastData(): void
{
$this->importPHPDataSet(__DIR__ . '/Fixtures/RemovePastTestDatabase.php');

View file

@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
return [
'be_users' => [
[
'uid' => 1,
'pid' => 0,
'tstamp' => 1366642540,
'username' => 'admin',
'password' => '$1$tCrlLajZ$C0sikFQQ3SWaFAZ1Me0Z/1', // password
'admin' => 1,
'disable' => 0,
'crdate' => 1366642540,
'deleted' => 0,
],
],
];

View file

@ -27,14 +27,14 @@ use Codappix\Typo3PhpDatasets\PhpDataSet;
use DateTimeImmutable;
use DateTimeZone;
use GuzzleHttp\Psr7\Response;
use PHPUnit\Framework\Attributes\Test;
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend;
use TYPO3\CMS\Core\Cache\CacheManager;
use TYPO3\CMS\Core\Information\Typo3Version;
use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequest;
use WerkraumMedia\Events\Tests\Functional\AbstractFunctionalTestCase;
/**
* @covers \WerkraumMedia\Events\Caching\PageCacheTimeout
*/
class CacheTest extends AbstractFunctionalTestCase
{
protected function setUp(): void
@ -42,9 +42,28 @@ class CacheTest extends AbstractFunctionalTestCase
$this->testExtensionsToLoad = [
'typo3conf/ext/events/Tests/Functional/Frontend/Fixtures/Extensions/example',
];
$this->configurationToUseInTestInstance = [
'SYS' => [
// Combined with flushCaches.
// Ensures that we have expected TYPO3 caching within each test.
// But we don't keep caches from one test to the other.
'caching' => [
'cacheConfigurations' => [
'pages' => [
'backend' => SimpleFileBackend::class,
'options' => [
'compression' => '__UNSET',
],
],
],
],
],
];
parent::setUp();
$this->get(CacheManager::class)->flushCaches();
$this->importPHPDataSet(__DIR__ . '/Fixtures/Database/SiteStructure.php');
(new PhpDataSet())->import(['tt_content' => [[
'uid' => '1',
@ -56,21 +75,17 @@ class CacheTest extends AbstractFunctionalTestCase
$this->setUpFrontendRendering();
}
/**
* @test
*/
#[Test]
public function returnsSystemDefaults(): void
{
$response = $this->executeFrontendRequest($this->getRequestWithSleep());
$response = $this->executeFrontendSubRequest($this->getRequestWithSleep());
self::assertSame(200, $response->getStatusCode());
self::assertSame('max-age=86400', $response->getHeaderLine('Cache-Control'));
self::assertSame('public', $response->getHeaderLine('Pragma'));
}
/**
* @test
*/
#[Test]
public function returnsDefaultsIfEventsEndLater(): void
{
(new PhpDataSet())->import([
@ -89,16 +104,14 @@ class CacheTest extends AbstractFunctionalTestCase
],
]);
$response = $this->executeFrontendRequest($this->getRequestWithSleep());
$response = $this->executeFrontendSubRequest($this->getRequestWithSleep());
self::assertSame(200, $response->getStatusCode());
self::assertSame('max-age=86400', $response->getHeaderLine('Cache-Control'));
self::assertSame('public', $response->getHeaderLine('Pragma'));
}
/**
* @test
*/
#[Test]
public function returnsEarlierIfEventsEndEarlier(): void
{
$end = (new DateTimeImmutable('tomorrow midnight', new DateTimeZone('UTC')))->modify('+2 hours');
@ -121,15 +134,13 @@ class CacheTest extends AbstractFunctionalTestCase
],
]);
$response = $this->executeFrontendRequest($this->getRequestWithSleep());
$response = $this->executeFrontendSubRequest($this->getRequestWithSleep());
self::assertSame(200, $response->getStatusCode());
self::assertCacheHeaders($end, $response);
}
/**
* @test
*/
#[Test]
public function returnsEarlierIfStartEndEalierAndIsUpcoming(): void
{
$end = (new DateTimeImmutable('now', new DateTimeZone('UTC')))->modify('+2 hours');
@ -152,7 +163,7 @@ class CacheTest extends AbstractFunctionalTestCase
],
]);
$response = $this->executeFrontendRequest($this->getRequestWithSleep([
$response = $this->executeFrontendSubRequest($this->getRequestWithSleep([
'plugin.' => [
'tx_events.' => [
'settings.' => [
@ -166,9 +177,7 @@ class CacheTest extends AbstractFunctionalTestCase
self::assertCacheHeaders($end, $response);
}
/**
* @test
*/
#[Test]
public function usesEarliestTimeout(): void
{
$end = (new DateTimeImmutable('now', new DateTimeZone('UTC')))->modify('+2 hours');
@ -202,7 +211,7 @@ class CacheTest extends AbstractFunctionalTestCase
],
]);
$response = $this->executeFrontendRequest($this->getRequestWithSleep([
$response = $this->executeFrontendSubRequest($this->getRequestWithSleep([
'plugin.' => [
'tx_events.' => [
'settings.' => [
@ -216,9 +225,7 @@ class CacheTest extends AbstractFunctionalTestCase
self::assertCacheHeaders($end, $response);
}
/**
* @test
*/
#[Test]
public function returnsMidnightIfConfigured(): void
{
$midnight = (new DateTimeImmutable('tomorrow midnight', new DateTimeZone('UTC')));
@ -247,21 +254,19 @@ class CacheTest extends AbstractFunctionalTestCase
],
]));
$response = $this->executeFrontendRequest($this->getRequestWithSleep());
$response = $this->executeFrontendSubRequest($this->getRequestWithSleep());
self::assertSame(200, $response->getStatusCode());
self::assertCacheHeaders($midnight, $response);
self::assertSame('public', $response->getHeaderLine('Pragma'));
}
/**
* @test
*/
#[Test]
public function cachesAreClearedByImport(): void
{
// Assert frontend is cached
$this->assertResponseIsNotCached($this->executeFrontendRequest($this->getRequestWithSleep()));
$this->assertResponseIsCached($this->executeFrontendRequest($this->getRequestWithSleep()));
$this->assertResponseIsNotCached($this->executeFrontendSubRequest($this->getRequestWithSleep()));
$this->assertResponseIsCached($this->executeFrontendSubRequest($this->getRequestWithSleep()));
// Import
$this->importPHPDataSet(__DIR__ . '/../Import/DestinationDataTest/Fixtures/Database/DefaultImportConfiguration.php');
@ -281,8 +286,8 @@ class CacheTest extends AbstractFunctionalTestCase
// Assert frontend is not cached on first hit
$this->setUpFrontendRendering();
$this->assertResponseIsNotCached($this->executeFrontendRequest($this->getRequestWithSleep()));
$this->assertResponseIsCached($this->executeFrontendRequest($this->getRequestWithSleep()));
$this->assertResponseIsNotCached($this->executeFrontendSubRequest($this->getRequestWithSleep()));
$this->assertResponseIsCached($this->executeFrontendSubRequest($this->getRequestWithSleep()));
}
private static function assertCacheHeaders(DateTimeImmutable $end, ResponseInterface $response): void
@ -316,10 +321,6 @@ class CacheTest extends AbstractFunctionalTestCase
private function assertResponseIsCached(ResponseInterface $response): void
{
if ((new Typo3Version())->getMajorVersion() < 11) {
self::assertStringContainsString('Cached page', $response->getBody()->__toString());
return;
}
self::assertStringStartsWith('Cached page', $response->getHeaderLine('X-TYPO3-Debug-Cache'));
}

View file

@ -23,13 +23,11 @@ declare(strict_types=1);
namespace WerkraumMedia\Events\Tests\Functional\Frontend;
use PHPUnit\Framework\Attributes\Test;
use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequest;
use WerkraumMedia\Events\Frontend\Dates;
use WerkraumMedia\Events\Tests\Functional\AbstractFunctionalTestCase;
/**
* @covers \WerkraumMedia\Events\Frontend\Dates
*/
class DatesTest extends AbstractFunctionalTestCase
{
protected function setUp(): void
@ -46,16 +44,15 @@ class DatesTest extends AbstractFunctionalTestCase
* Dates don't make any sense without an event, as they not even have a name.
*
* They therefore should not be fetched from persistence.
*
* @test
*/
#[Test]
public function returnsOnlyDatesWithAvailableEventByDemand(): void
{
$this->importCSVDataSet(__DIR__ . '/DatesTestFixtures/ReturnsOnlyDatesWithAvailableEventByDemand.csv');
$this->importPHPDataSet(__DIR__ . '/DatesTestFixtures/ReturnsOnlyDatesWithAvailableEventByDemand.php');
$request = new InternalRequest();
$request = $request->withPageId(1);
$response = $this->executeFrontendRequest($request);
$response = $this->executeFrontendSubRequest($request);
self::assertSame(200, $response->getStatusCode());
$html = (string)$response->getBody();
@ -64,19 +61,17 @@ class DatesTest extends AbstractFunctionalTestCase
self::assertStringContainsString('Event 2 visible', $html);
}
/**
* @test
*/
#[Test]
public function returnsDateAfterStart(): void
{
$this->importCSVDataSet(__DIR__ . '/DatesTestFixtures/ReturnsDateWithinTimeSpan.csv');
$this->importPHPDataSet(__DIR__ . '/DatesTestFixtures/ReturnsDateWithinTimeSpan.php');
$request = new InternalRequest();
$request = $request->withPageId(1);
$request = $request->withQueryParameters([
'events_search[search][start]' => '2023-02-16',
]);
$response = $this->executeFrontendRequest($request);
$response = $this->executeFrontendSubRequest($request);
self::assertSame(200, $response->getStatusCode());
$html = (string)$response->getBody();
@ -92,19 +87,17 @@ class DatesTest extends AbstractFunctionalTestCase
self::assertStringContainsString('Event 9', $html);
}
/**
* @test
*/
#[Test]
public function returnsDateBeforeEnd(): void
{
$this->importCSVDataSet(__DIR__ . '/DatesTestFixtures/ReturnsDateWithinTimeSpan.csv');
$this->importPHPDataSet(__DIR__ . '/DatesTestFixtures/ReturnsDateWithinTimeSpan.php');
$request = new InternalRequest();
$request = $request->withPageId(1);
$request = $request->withQueryParameters([
'events_search[search][end]' => '2023-02-17',
]);
$response = $this->executeFrontendRequest($request);
$response = $this->executeFrontendSubRequest($request);
self::assertSame(200, $response->getStatusCode());
$html = (string)$response->getBody();
@ -124,12 +117,11 @@ class DatesTest extends AbstractFunctionalTestCase
* Covers issue https://redmine.werkraum-media.de/issues/10350.
* A date can span multiple dates.
* The visitor might search a time frame within the spaned dates and expects the date to be shown.
*
* @test
*/
#[Test]
public function returnsDateWithinTimeSpan(): void
{
$this->importCSVDataSet(__DIR__ . '/DatesTestFixtures/ReturnsDateWithinTimeSpan.csv');
$this->importPHPDataSet(__DIR__ . '/DatesTestFixtures/ReturnsDateWithinTimeSpan.php');
$request = new InternalRequest();
$request = $request->withPageId(1);
@ -137,7 +129,7 @@ class DatesTest extends AbstractFunctionalTestCase
'events_search[search][start]' => '2023-02-16',
'events_search[search][end]' => '2023-02-17',
]);
$response = $this->executeFrontendRequest($request);
$response = $this->executeFrontendSubRequest($request);
self::assertSame(200, $response->getStatusCode());
$html = (string)$response->getBody();
@ -153,26 +145,22 @@ class DatesTest extends AbstractFunctionalTestCase
self::assertStringContainsString('Event 9', $html);
}
/**
* @test
*/
#[Test]
public function returns404IfEventIsHidden(): void
{
$this->importCSVDataSet(__DIR__ . '/DatesTestFixtures/Returns404IfEventIsHidden.csv');
$this->importPHPDataSet(__DIR__ . '/DatesTestFixtures/Returns404IfEventIsHidden.php');
$request = new InternalRequest();
$request = $request->withPageId(1);
$request = $request->withQueryParameters([
'tx_events_dateshow[date]' => '1',
]);
$response = $this->executeFrontendRequest($request);
$response = $this->executeFrontendSubRequest($request);
self::assertSame(404, $response->getStatusCode());
}
/**
* @test
*/
#[Test]
public function returnsUpcomingDates(): void
{
$this->importPHPDataSet(__DIR__ . '/DatesTestFixtures/ReturnsUpcomingDates.php');
@ -191,7 +179,7 @@ class DatesTest extends AbstractFunctionalTestCase
],
]),
]);
$response = $this->executeFrontendRequest($request);
$response = $this->executeFrontendSubRequest($request);
self::assertSame(200, $response->getStatusCode());
$html = (string)$response->getBody();

View file

@ -1,9 +0,0 @@
tt_content
,uid,pid,CType,list_type,header
,1,1,list,events_dateshow,Singleview
tx_events_domain_model_event
,uid,pid,title,hidden
,1,2,"Event 1 starts before search, ends before search",1
tx_events_domain_model_date
,uid,pid,event,start,end
,1,2,1,1676419200,1676484000
Can't render this file because it has a wrong number of fields in line 2.

View file

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
return [
'tt_content' => [
0 => [
'uid' => '1',
'pid' => '1',
'CType' => 'list',
'list_type' => 'events_dateshow',
'header' => 'Singleview',
],
],
'tx_events_domain_model_event' => [
0 => [
'uid' => '1',
'pid' => '2',
'title' => 'Event 1 starts before search, ends before search',
'hidden' => '1',
],
],
'tx_events_domain_model_date' => [
0 => [
'uid' => '1',
'pid' => '2',
'event' => '1',
'start' => '1676419200',
'end' => '1676484000',
],
],
];

View file

@ -1,25 +0,0 @@
tt_content
,uid,pid,CType,list_type,header
,1,1,list,events_datelist,All Dates
tx_events_domain_model_event
,uid,pid,title
,1,2,Event 1 starts before search, ends before search
,2,2,Event 2 starts before search, no end
,3,2,Event 3 starts after search, ends after search
,4,2,Event 4 starts after search, no end
,5,2,Event 5 starts before search, ends after search
,6,2,Event 6 starts inside search, ends inside search
,7,2,Event 7 starts inside search, ends after search
,8,2,Event 8 starts inside search, no end
,9,2,Event 9 starts before search, ends inside search
tx_events_domain_model_date
,uid,pid,event,start,end
,1,2,1,1676419200,1676484000
,2,2,2,1676419200,"\NULL"
,3,2,3,1676678400,1676743200
,4,2,4,1676678400,"\NULL"
,5,2,5,1676419200,1676678400
,6,2,6,1676559600,1676570400
,7,2,7,1676559600,1676678400
,8,2,8,1676559600,"\NULL"
,9,2,9,1676419200,1676570400
Can't render this file because it has a wrong number of fields in line 2.

View file

@ -0,0 +1,127 @@
<?php
declare(strict_types=1);
return [
'tt_content' => [
0 => [
'uid' => '1',
'pid' => '1',
'CType' => 'list',
'list_type' => 'events_datelist',
'header' => 'All Dates',
],
],
'tx_events_domain_model_event' => [
0 => [
'uid' => '1',
'pid' => '2',
'title' => 'Event 1 starts before search, ends before search',
],
1 => [
'uid' => '2',
'pid' => '2',
'title' => 'Event 2 starts before search, no end',
],
2 => [
'uid' => '3',
'pid' => '2',
'title' => 'Event 3 starts after search, ends after search',
],
3 => [
'uid' => '4',
'pid' => '2',
'title' => 'Event 4 starts after search, no end',
],
4 => [
'uid' => '5',
'pid' => '2',
'title' => 'Event 5 starts before search, ends after search',
],
5 => [
'uid' => '6',
'pid' => '2',
'title' => 'Event 6 starts inside search, ends inside search',
],
6 => [
'uid' => '7',
'pid' => '2',
'title' => 'Event 7 starts inside search, ends after search',
],
7 => [
'uid' => '8',
'pid' => '2',
'title' => 'Event 8 starts inside search, no end',
],
8 => [
'uid' => '9',
'pid' => '2',
'title' => 'Event 9 starts before search, ends inside search',
],
],
'tx_events_domain_model_date' => [
0 => [
'uid' => '1',
'pid' => '2',
'event' => '1',
'start' => '1676419200',
'end' => '1676484000',
],
1 => [
'uid' => '2',
'pid' => '2',
'event' => '2',
'start' => '1676419200',
'end' => '\\NULL',
],
2 => [
'uid' => '3',
'pid' => '2',
'event' => '3',
'start' => '1676678400',
'end' => '1676743200',
],
3 => [
'uid' => '4',
'pid' => '2',
'event' => '4',
'start' => '1676678400',
'end' => '\\NULL',
],
4 => [
'uid' => '5',
'pid' => '2',
'event' => '5',
'start' => '1676419200',
'end' => '1676678400',
],
5 => [
'uid' => '6',
'pid' => '2',
'event' => '6',
'start' => '1676559600',
'end' => '1676570400',
],
6 => [
'uid' => '7',
'pid' => '2',
'event' => '7',
'start' => '1676559600',
'end' => '1676678400',
],
7 => [
'uid' => '8',
'pid' => '2',
'event' => '8',
'start' => '1676559600',
'end' => '\\NULL',
],
8 => [
'uid' => '9',
'pid' => '2',
'event' => '9',
'start' => '1676419200',
'end' => '1676570400',
],
],
];

View file

@ -1,11 +0,0 @@
tt_content
,uid,pid,CType,list_type,header
,1,1,list,events_datelist,All Dates
tx_events_domain_model_event
,uid,pid,title,hidden
,1,2,Event 1 hidden,1
,2,2,Event 2 visible,0
tx_events_domain_model_date
,uid,pid,event,start,end
,1,2,1,1662458400,1662469200
,2,2,2,1662458400,1662469200
1 tt_content
2 ,uid,pid,CType,list_type,header
3 ,1,1,list,events_datelist,All Dates
4 tx_events_domain_model_event
5 ,uid,pid,title,hidden
6 ,1,2,Event 1 hidden,1
7 ,2,2,Event 2 visible,0
8 tx_events_domain_model_date
9 ,uid,pid,event,start,end
10 ,1,2,1,1662458400,1662469200
11 ,2,2,2,1662458400,1662469200

View file

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
return [
'tt_content' => [
0 => [
'uid' => '1',
'pid' => '1',
'CType' => 'list',
'list_type' => 'events_datelist',
'header' => 'All Dates',
],
],
'tx_events_domain_model_event' => [
0 => [
'uid' => '1',
'pid' => '2',
'title' => 'Event 1 hidden',
'hidden' => '1',
],
1 => [
'uid' => '2',
'pid' => '2',
'title' => 'Event 2 visible',
'hidden' => '0',
],
],
'tx_events_domain_model_date' => [
0 => [
'uid' => '1',
'pid' => '2',
'event' => '1',
'start' => '1662458400',
'end' => '1662469200',
],
1 => [
'uid' => '2',
'pid' => '2',
'event' => '2',
'start' => '1662458400',
'end' => '1662469200',
],
],
];

View file

@ -1,6 +1,6 @@
<?php
use DateTimeImmutable;
declare(strict_types=1);
return [
'tt_content' => [

View file

@ -4,13 +4,10 @@ declare(strict_types=1);
namespace WerkraumMedia\Events\Tests\Functional\Frontend;
use PHPUnit\Framework\Attributes\Test;
use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequest;
use WerkraumMedia\Events\Tests\Functional\AbstractFunctionalTestCase;
/**
* @covers \WerkraumMedia\Events\Controller\DateController
* @covers \WerkraumMedia\Events\Domain\Repository\DateRepository
*/
class FilterTest extends AbstractFunctionalTestCase
{
protected function setUp(): void
@ -21,16 +18,14 @@ class FilterTest extends AbstractFunctionalTestCase
$this->setUpFrontendRendering();
}
/**
* @test
*/
#[Test]
public function canFilterByASingleLocationViaFlexform(): void
{
$this->importPHPDataSet(__DIR__ . '/Fixtures/Database/FilterByASingleLocationViaFlexform.php');
$request = new InternalRequest();
$request = $request->withPageId(1);
$response = $this->executeFrontendRequest($request);
$response = $this->executeFrontendSubRequest($request);
self::assertSame(200, $response->getStatusCode());
$html = (string)$response->getBody();
@ -39,16 +34,14 @@ class FilterTest extends AbstractFunctionalTestCase
self::assertStringContainsString('Was hat das Universum mit mir zu tun?', $html);
}
/**
* @test
*/
#[Test]
public function canFilterByTwoLocationsViaFlexform(): void
{
$this->importPHPDataSet(__DIR__ . '/Fixtures/Database/FilterByTwoLocationsViaFlexform.php');
$request = new InternalRequest();
$request = $request->withPageId(1);
$response = $this->executeFrontendRequest($request);
$response = $this->executeFrontendSubRequest($request);
self::assertSame(200, $response->getStatusCode());
$html = (string)$response->getBody();

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
return [
'tt_content' => [
[

Some files were not shown because too many files have changed in this diff Show more