Add TYPO3 13 LTS Support

Relates: #11322
This commit is contained in:
Daniel Siepmann 2024-08-19 15:22:56 +02:00 committed by Daniel Siepmann
parent 60b752e4b2
commit db81cd4d88
73 changed files with 773 additions and 473 deletions
.github/workflows
Classes
Configuration
Documentation
Resources/Private/Language
Tests
composer.jsonext_emconf.phpext_localconf.phpphpstan-baseline.neon

View file

@ -90,6 +90,10 @@ jobs:
typo3-version: '^12.4' typo3-version: '^12.4'
- php-version: '8.3' - php-version: '8.3'
typo3-version: '^12.4' typo3-version: '^12.4'
- php-version: '8.2'
typo3-version: '^13.4'
- php-version: '8.3'
typo3-version: '^13.4'
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
@ -119,6 +123,10 @@ jobs:
typo3-version: '^12.4' typo3-version: '^12.4'
- php-version: '8.3' - php-version: '8.3'
typo3-version: '^12.4' typo3-version: '^12.4'
- php-version: '8.2'
typo3-version: '^13.4'
- php-version: '8.3'
typo3-version: '^13.4'
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3

View file

@ -26,7 +26,6 @@ namespace WerkraumMedia\Events\Caching;
use DateTime; use DateTime;
use DateTimeImmutable; use DateTimeImmutable;
use InvalidArgumentException; use InvalidArgumentException;
use TYPO3\CMS\Core\Cache\CacheManager;
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface; use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
use TYPO3\CMS\Core\Context\Context; use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\SingletonInterface; use TYPO3\CMS\Core\SingletonInterface;
@ -44,13 +43,10 @@ class PageCacheTimeout implements SingletonInterface
{ {
private ?DateTimeImmutable $timeout = null; private ?DateTimeImmutable $timeout = null;
private FrontendInterface $runtimeCache;
public function __construct( public function __construct(
CacheManager $cacheManager, private readonly FrontendInterface $runtimeCache,
private readonly Context $context private readonly Context $context,
) { ) {
$this->runtimeCache = $cacheManager->getCache('runtime');
} }
public function modifyCacheLifetimeForPage(ModifyCacheLifetimeForPageEvent $event): void public function modifyCacheLifetimeForPage(ModifyCacheLifetimeForPageEvent $event): void

View file

@ -25,13 +25,14 @@ namespace WerkraumMedia\Events\Controller;
use TYPO3\CMS\Core\Http\PropagateResponseException; use TYPO3\CMS\Core\Http\PropagateResponseException;
use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\View\ViewInterface;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
use TYPO3\CMS\Frontend\Controller\ErrorController; use TYPO3\CMS\Frontend\Controller\ErrorController;
use TYPO3Fluid\Fluid\View\ViewInterface; use TYPO3Fluid\Fluid\View\ViewInterface as FluidStandaloneViewInterface;
use WerkraumMedia\Events\Caching\CacheManager; use WerkraumMedia\Events\Caching\CacheManager;
class AbstractController extends ActionController abstract class AbstractController extends ActionController
{ {
/** /**
* @var CacheManager * @var CacheManager
@ -60,17 +61,13 @@ class AbstractController extends ActionController
/** /**
* Extend original to also add data from current cobject if available. * Extend original to also add data from current cobject if available.
*/ */
protected function resolveView(): ViewInterface protected function initializeView(ViewInterface|FluidStandaloneViewInterface $view): void
{ {
$view = parent::resolveView();
$view->assign('data', []); $view->assign('data', []);
$cObject = $this->request->getAttribute('currentContentObject'); $cObject = $this->request->getAttribute('currentContentObject');
if ($cObject instanceof ContentObjectRenderer && is_array($cObject->data)) { if ($cObject instanceof ContentObjectRenderer && is_array($cObject->data)) {
$view->assign('data', $cObject->data); $view->assign('data', $cObject->data);
} }
return $view;
} }
protected function trigger404(string $message): void protected function trigger404(string $message): void

View file

@ -5,13 +5,13 @@ declare(strict_types=1);
namespace WerkraumMedia\Events\Domain\DestinationData; namespace WerkraumMedia\Events\Domain\DestinationData;
use Exception; use Exception;
use PDO;
use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Resource\Folder; use TYPO3\CMS\Core\Resource\Folder;
use TYPO3\CMS\Core\Resource\ResourceFactory; use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper; use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper;
use TYPO3\CMS\Extbase\Persistence\Generic\Session; use TYPO3\CMS\Extbase\Persistence\Generic\Session;
use WerkraumMedia\Events\Domain\Model\Import; use WerkraumMedia\Events\Domain\Model\Import;
use WerkraumMedia\Events\Service\ExtbaseConfigurationManagerService;
final class ImportFactory final class ImportFactory
{ {
@ -24,7 +24,8 @@ final class ImportFactory
private readonly ConnectionPool $connectionPool, private readonly ConnectionPool $connectionPool,
private readonly Session $extbasePersistenceSession, private readonly Session $extbasePersistenceSession,
private readonly DataMapper $dataMapper, private readonly DataMapper $dataMapper,
private readonly ResourceFactory $resourceFactory private readonly ResourceFactory $resourceFactory,
private readonly ExtbaseConfigurationManagerService $extbaseConfigurationManagerService,
) { ) {
} }
@ -49,14 +50,14 @@ final class ImportFactory
$qb = $this->connectionPool->getQueryBuilderForTable('tx_events_domain_model_import'); $qb = $this->connectionPool->getQueryBuilderForTable('tx_events_domain_model_import');
$qb->select('*'); $qb->select('*');
$qb->from('tx_events_domain_model_import'); $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)));
$result = $qb->executeQuery()->fetch(); $result = $qb->executeQuery()->fetchAssociative();
if (is_array($result) === false) { 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); $result = array_map(strval(...), $result);
return $result; return $result;
} }
@ -67,13 +68,13 @@ final class ImportFactory
$qb->select('*'); $qb->select('*');
$qb->from('tx_events_domain_model_import'); $qb->from('tx_events_domain_model_import');
$result = $qb->executeQuery()->fetchAll(); $result = $qb->executeQuery()->fetchAllAssociative();
if (count($result) === 0) { 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) { foreach ($result as $key => $entry) {
$result[$key] = array_map('strval', $entry); $result[$key] = array_map(strval(...), $entry);
} }
return $result; return $result;
@ -94,6 +95,7 @@ final class ImportFactory
{ {
$this->folderInstance = $this->resourceFactory->getFolderObjectFromCombinedIdentifier($data['files_folder']); $this->folderInstance = $this->resourceFactory->getFolderObjectFromCombinedIdentifier($data['files_folder']);
$this->extbasePersistenceSession->registerObject($this->folderInstance, $data['files_folder']); $this->extbasePersistenceSession->registerObject($this->folderInstance, $data['files_folder']);
$this->extbaseConfigurationManagerService->configureForBackend();
} }
private function cleanupWorkarounds(): void private function cleanupWorkarounds(): void

View file

@ -75,7 +75,7 @@ final class CategoryRepository extends Repository
return $this->dataMapper->map( return $this->dataMapper->map(
Category::class, Category::class,
$qb->executeQuery()->fetchAll() $qb->executeQuery()->fetchAllAssociative()
); );
} }

View file

@ -304,7 +304,7 @@ final class DateRepository extends Repository
)->orderBy('tx_events_domain_model_date.start') )->orderBy('tx_events_domain_model_date.start')
; ;
return $statement->executeQuery()->fetchAll(); return $statement->executeQuery()->fetchAllAssociative();
} }
private function createEventConstraint( private function createEventConstraint(

View file

@ -18,7 +18,18 @@ namespace WerkraumMedia\Events\Domain\Repository;
*/ */
use TYPO3\CMS\Extbase\Persistence\Repository; use TYPO3\CMS\Extbase\Persistence\Repository;
use WerkraumMedia\Events\Domain\Model\Organizer;
final class OrganizerRepository extends Repository final class OrganizerRepository extends Repository
{ {
public function findOneByName(string $name): ?Organizer
{
$organizer = $this->findOneBy(['name' => $name]);
if ($organizer instanceof Organizer) {
return $organizer;
}
return null;
}
} }

View file

@ -72,7 +72,7 @@ final class AddSpecialProperties
$qb->where($qb->expr()->eq('postponed_date', $uidOfReferencedDate)); $qb->where($qb->expr()->eq('postponed_date', $uidOfReferencedDate));
$qb->setMaxResults(1); $qb->setMaxResults(1);
$result = $qb->executeQuery()->fetch(); $result = $qb->executeQuery()->fetchAssociative();
if ($result === false) { if ($result === false) {
return null; return null;

View file

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace WerkraumMedia\Events\Service; namespace WerkraumMedia\Events\Service;
use RuntimeException;
use TYPO3\CMS\Core\Cache\CacheManager; use TYPO3\CMS\Core\Cache\CacheManager;
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface; use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
use TYPO3\CMS\Core\Database\Connection; use TYPO3\CMS\Core\Database\Connection;
@ -13,9 +14,9 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
final class CategoryService final class CategoryService
{ {
private TimeTracker $timeTracker; private readonly TimeTracker $timeTracker;
private FrontendInterface $cache; private readonly FrontendInterface $cache;
public function __construct() public function __construct()
{ {
@ -77,17 +78,18 @@ final class CategoryService
->executeQuery() ->executeQuery()
; ;
while ($row = $res->fetch()) { foreach ($res->fetchAllAssociative() as $row) {
if (is_array($row) === false) {
continue;
}
$counter++; $counter++;
if ($counter > 10000) { if ($counter > 10000) {
$this->timeTracker->setTSlogMessage('EXT:dd_events: one or more recursive categories where found'); $this->timeTracker->setTSlogMessage('EXT:dd_events: one or more recursive categories where found');
return implode(',', $result); return implode(',', $result);
} }
$subcategories = $this->getChildrenCategoriesRecursive($row['uid'], $counter); $uid = $row['uid'];
if (is_numeric($uid) === false) {
throw new RuntimeException('Given uid was not numeric, which we never expect as UID column within DB is numeric.', 1728998121);
}
$subcategories = $this->getChildrenCategoriesRecursive((string)$uid, $counter);
$result[] = $row['uid'] . ($subcategories ? ',' . $subcategories : ''); $result[] = $row['uid'] . ($subcategories ? ',' . $subcategories : '');
} }
@ -100,11 +102,10 @@ final class CategoryService
*/ */
protected function getUidListFromRecords(string $idList): string protected function getUidListFromRecords(string $idList): string
{ {
$list = [];
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable('sys_category') ->getQueryBuilderForTable('sys_category')
; ;
$rows = $queryBuilder $uids = $queryBuilder
->select('uid') ->select('uid')
->from('sys_category') ->from('sys_category')
->where($queryBuilder->expr()->in( ->where($queryBuilder->expr()->in(
@ -112,16 +113,9 @@ final class CategoryService
$queryBuilder->createNamedParameter(explode(',', $idList), Connection::PARAM_INT_ARRAY) $queryBuilder->createNamedParameter(explode(',', $idList), Connection::PARAM_INT_ARRAY)
)) ))
->executeQuery() ->executeQuery()
->fetchAll() ->fetchFirstColumn()
; ;
foreach ($rows as $row) {
if (is_array($row) === false) {
continue;
}
$list[] = $row['uid']; return implode(',', $uids);
}
return implode(',', $list);
} }
} }

View file

@ -24,7 +24,6 @@ namespace WerkraumMedia\Events\Service\Cleanup;
*/ */
use DateTimeImmutable; use DateTimeImmutable;
use PDO;
use TYPO3\CMS\Core\Database\Connection; use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Database\ConnectionPool;
@ -88,7 +87,7 @@ final class Database
$recordUids = $queryBuilder->select('event.uid') $recordUids = $queryBuilder->select('event.uid')
->from(self::EVENT_TABLE, 'event') ->from(self::EVENT_TABLE, 'event')
->leftJoin('event', self::DATE_TABLE, 'date', $queryBuilder->expr()->eq('date.event', 'event.uid'))->where($queryBuilder->expr()->isNull('date.uid'))->executeQuery() ->leftJoin('event', self::DATE_TABLE, 'date', $queryBuilder->expr()->eq('date.event', 'event.uid'))->where($queryBuilder->expr()->isNull('date.uid'))->executeQuery()
->fetchAll(PDO::FETCH_COLUMN) ->fetchFirstColumn()
; ;
$queryBuilder = $this->connectionPool->getQueryBuilderForTable(self::EVENT_TABLE); $queryBuilder = $this->connectionPool->getQueryBuilderForTable(self::EVENT_TABLE);

View file

@ -23,7 +23,7 @@ namespace WerkraumMedia\Events\Service\Cleanup;
* 02110-1301, USA. * 02110-1301, USA.
*/ */
use PDO; use RuntimeException;
use TYPO3\CMS\Core\Database\Connection; use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Resource\StorageRepository; use TYPO3\CMS\Core\Resource\StorageRepository;
@ -84,16 +84,12 @@ final class Files
$referencesQuery->orderBy('tablenames'); $referencesQuery->orderBy('tablenames');
$referencesQuery->addOrderBy('uid_foreign'); $referencesQuery->addOrderBy('uid_foreign');
$references = $referencesQuery->executeQuery(); $references = $referencesQuery->executeQuery()->fetchAllAssociative();
$uidsPerTable = []; $uidsPerTable = [];
$referenceUidsToMarkAsDeleted = []; $referenceUidsToMarkAsDeleted = [];
while ($reference = $references->fetch()) { foreach ($references as $reference) {
if (is_array($reference) === false) {
continue;
}
if ($reference['tablenames'] === '') { if ($reference['tablenames'] === '') {
$referenceUidsToMarkAsDeleted[] = $reference['uid']; $referenceUidsToMarkAsDeleted[] = $reference['uid'];
continue; continue;
@ -112,7 +108,7 @@ final class Files
...$referenceUidsToMarkAsDeleted, ...$referenceUidsToMarkAsDeleted,
...array_keys(array_diff( ...array_keys(array_diff(
$records, $records,
$queryBuilder->executeQuery()->fetchAll(PDO::FETCH_COLUMN) $queryBuilder->executeQuery()->fetchFirstColumn()
)), )),
]; ];
} }
@ -249,11 +245,16 @@ final class Files
foreach ($queryBuilder->executeQuery()->iterateAssociative() as $reference) { foreach ($queryBuilder->executeQuery()->iterateAssociative() as $reference) {
$file = []; $file = [];
$fileUid = (int)$reference['uid_local']; $fileUid = (int)$reference['uid_local'];
$tableNames = $reference['tablenames'];
if (is_string($tableNames) === false) {
throw new RuntimeException('Fetched "tablenames" was not of type string. But it should be a string within the db.', 1728998600);
}
if ( if (
( (
str_starts_with((string)$reference['tablenames'], 'tx_events_domain_model_') str_starts_with($tableNames, 'tx_events_domain_model_')
|| $reference['tablenames'] === '' || $tableNames === ''
) && $reference['deleted'] == 1 ) && $reference['deleted'] == 1
) { ) {
$file = $files[$fileUid] ?? []; $file = $files[$fileUid] ?? [];

View file

@ -113,7 +113,14 @@ final class DataProcessingForModels implements SingletonInterface
private function getData(AbstractEntity $entity): array private function getData(AbstractEntity $entity): array
{ {
$row = $this->connection->select(['*'], $this->getTable($entity), ['uid' => $entity->getUid()])->fetch(); $row = $this->connection
->select(
['*'],
$this->getTable($entity),
['uid' => $entity->getUid()]
)
->fetchAssociative()
;
if (is_array($row)) { if (is_array($row)) {
return $row; return $row;
} }

View file

@ -38,14 +38,8 @@ final class DestinationDataImportService
private Event $tmpCurrentEvent; private Event $tmpCurrentEvent;
/** private readonly Logger $logger;
* @var Logger
*/
private $logger;
/**
* ImportService constructor.
*/
public function __construct( public function __construct(
private readonly EventRepository $eventRepository, private readonly EventRepository $eventRepository,
private readonly OrganizerRepository $organizerRepository, private readonly OrganizerRepository $organizerRepository,
@ -60,8 +54,10 @@ final class DestinationDataImportService
private readonly Slugger $slugger, private readonly Slugger $slugger,
private readonly CacheManager $cacheManager, private readonly CacheManager $cacheManager,
private readonly DataHandler $dataHandler, private readonly DataHandler $dataHandler,
private readonly EventDispatcher $eventDispatcher private readonly EventDispatcher $eventDispatcher,
LogManager $logManager,
) { ) {
$this->logger = $logManager->getLogger(self::class);
} }
public function import( public function import(
@ -83,7 +79,6 @@ final class DestinationDataImportService
// Set Configuration // Set Configuration
$this->configurationManager->setConfiguration(array_merge($frameworkConfiguration, $persistenceConfiguration)); $this->configurationManager->setConfiguration(array_merge($frameworkConfiguration, $persistenceConfiguration));
$this->logger = GeneralUtility::makeInstance(LogManager::class)->getLogger(self::class);
$this->logger->info('Starting Destination Data Import Service'); $this->logger->info('Starting Destination Data Import Service');
try { try {
@ -412,7 +407,7 @@ final class DestinationDataImportService
private function getOrCreateEvent(string $globalId, string $title): Event private function getOrCreateEvent(string $globalId, string $title): Event
{ {
$event = $this->eventRepository->findOneByGlobalId($globalId); $event = $this->eventRepository->findOneBy(['globalId' => $globalId]);
if ($event instanceof Event) { if ($event instanceof Event) {
$this->logger->info( $this->logger->info(

View file

@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Service\DestinationDataImportService;
final class ArrayBasedConfigurationService implements ConfigurationServiceInterface
{
public function __construct(
private readonly array $settings
) {
}
public function getLicenseKey(): string
{
return $this->settings['license'] ?? '';
}
public function getRestType(): string
{
return $this->settings['restType'] ?? '';
}
public function getRestMode(): string
{
return $this->settings['restMode'] ?? '';
}
public function getRestLimit(): string
{
return $this->settings['restLimit'] ?? '';
}
public function getRestTemplate(): string
{
return $this->settings['restTemplate'] ?? '';
}
public function getRestUrl(): string
{
return $this->settings['restUrl'] ?? '';
}
}

View file

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Service\DestinationDataImportService;
interface ConfigurationServiceInterface
{
public function getLicenseKey(): string;
public function getRestType(): string;
public function getRestMode(): string;
public function getRestLimit(): string;
public function getRestTemplate(): string;
public function getRestUrl(): string;
}

View file

@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Service\DestinationDataImportService;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use WerkraumMedia\Events\Service\ExtbaseConfigurationManagerService;
final class ExtbaseConfigurationService implements ConfigurationServiceInterface
{
private array $settings = [];
public function __construct(
private ExtbaseConfigurationManagerService $configurationManager
) {
}
public function getLicenseKey(): string
{
return $this->getSettings()['license'] ?? '';
}
public function getRestType(): string
{
return $this->getSettings()['restType'] ?? '';
}
public function getRestMode(): string
{
return $this->getSettings()['restMode'] ?? '';
}
public function getRestLimit(): string
{
return $this->getSettings()['restLimit'] ?? '';
}
public function getRestTemplate(): string
{
return $this->getSettings()['restTemplate'] ?? '';
}
public function getRestUrl(): string
{
return $this->getSettings()['restUrl'] ?? '';
}
private function getSettings(): array
{
if ($this->settings !== []) {
return $this->settings;
}
$fullTypoScript = $this->configurationManager
->getInstanceWithBackendContext()
->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT)
;
$this->settings = $fullTypoScript['module.']['tx_events.']['settings.']['destinationData.']
?? $fullTypoScript['module.']['tx_events_pi1.']['settings.']['destinationData.']
?? [];
return $this->settings;
}
}

View file

@ -27,7 +27,8 @@ use Exception;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use SplFileInfo; use SplFileInfo;
use TYPO3\CMS\Core\Log\LogManager; use TYPO3\CMS\Core\Log\LogManager;
use TYPO3\CMS\Core\Resource\DuplicationBehavior; use TYPO3\CMS\Core\Resource\DuplicationBehavior as OldDuplicationBehavior;
use TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior;
use TYPO3\CMS\Core\Resource\File; use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\Folder; use TYPO3\CMS\Core\Resource\Folder;
use TYPO3\CMS\Core\Resource\Index\MetaDataRepository; use TYPO3\CMS\Core\Resource\Index\MetaDataRepository;
@ -76,7 +77,14 @@ final class FilesAssignment
$this->logger->info('File already exists.', [$orgFileNameSanitized]); $this->logger->info('File already exists.', [$orgFileNameSanitized]);
} elseif ($filename = $this->loadFile($fileUrl)) { } elseif ($filename = $this->loadFile($fileUrl)) {
$this->logger->info('Adding file to FAL.', [$filename]); $this->logger->info('Adding file to FAL.', [$filename]);
$importFolder->addFile($filename, $orgFileNameSanitized, DuplicationBehavior::REPLACE);
// TODO: typo3/cms-core:14.0 Remove the fallback to old behaviour, only use new one.
$behaviour = OldDuplicationBehavior::REPLACE;
if (class_exists(DuplicationBehavior::class)) {
$behaviour = DuplicationBehavior::REPLACE;
}
$importFolder->addFile($filename, $orgFileNameSanitized, $behaviour);
} else { } else {
continue; continue;
} }

View file

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace WerkraumMedia\Events\Service\DestinationDataImportService; namespace WerkraumMedia\Events\Service\DestinationDataImportService;
use Generator; use Generator;
use PDO;
use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\QueryBuilder; use TYPO3\CMS\Core\Database\Query\QueryBuilder;
use TYPO3\CMS\Core\DataHandling\SlugHelper; use TYPO3\CMS\Core\DataHandling\SlugHelper;
@ -61,18 +60,14 @@ final class Slugger
->from($tableName) ->from($tableName)
->where( ->where(
$queryBuilder->expr()->or( $queryBuilder->expr()->or(
$queryBuilder->expr()->eq($slugColumn, $queryBuilder->createNamedParameter('', PDO::PARAM_STR)), $queryBuilder->expr()->eq($slugColumn, $queryBuilder->createNamedParameter('')),
$queryBuilder->expr()->isNull($slugColumn) $queryBuilder->expr()->isNull($slugColumn)
) )
) )
->executeQuery() ->executeQuery()
; ;
while ($record = $statement->fetch()) { foreach ($statement->iterateAssociative() as $record) {
if (is_array($record) === false) {
continue;
}
yield $record; yield $record;
} }
} }
@ -88,7 +83,7 @@ final class Slugger
->where( ->where(
$queryBuilder->expr()->eq( $queryBuilder->expr()->eq(
'uid', 'uid',
$queryBuilder->createNamedParameter($record['uid'], PDO::PARAM_INT) $queryBuilder->createNamedParameter((int)$record['uid'])
) )
) )
->set($sluggerType->getSlugColumn(), $slug) ->set($sluggerType->getSlugColumn(), $slug)

View file

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace WerkraumMedia\Events\Service\DestinationDataImportService; namespace WerkraumMedia\Events\Service\DestinationDataImportService;
use TYPO3\CMS\Core\Http\Uri; use TYPO3\CMS\Core\Http\Uri;
use TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager;
use WerkraumMedia\Events\Domain\Model\Import; use WerkraumMedia\Events\Domain\Model\Import;
/** /**
@ -13,18 +12,9 @@ use WerkraumMedia\Events\Domain\Model\Import;
*/ */
final class UrlFactory final class UrlFactory
{ {
/**
* @var array
*/
private $settings = [];
public function __construct( public function __construct(
BackendConfigurationManager $configurationManager private readonly ConfigurationServiceInterface $configuration,
) { ) {
$this->settings = $configurationManager->getConfiguration(
'Events',
'Pi1'
)['settings']['destinationData'] ?? [];
} }
/** /**
@ -35,17 +25,17 @@ final class UrlFactory
): string { ): string {
$parameter = [ $parameter = [
'experience' => $import->getRestExperience(), 'experience' => $import->getRestExperience(),
'licensekey' => $this->settings['license'] ?? '', 'licensekey' => $this->configuration->getLicenseKey(),
'type' => $this->settings['restType'] ?? '', 'type' => $this->configuration->getRestType(),
'mode' => $this->settings['restMode'] ?? '', 'mode' => $this->configuration->getRestMode(),
'limit' => $this->settings['restLimit'] ?? '', 'limit' => $this->configuration->getRestLimit(),
'template' => $this->settings['restTemplate'] ?? '', 'template' => $this->configuration->getRestTemplate(),
'q' => $import->getSearchQuery(), 'q' => $import->getSearchQuery(),
]; ];
$parameter = array_filter($parameter); $parameter = array_filter($parameter);
$url = new Uri($this->settings['restUrl']); $url = new Uri($this->configuration->getRestUrl());
$url = $url->withQuery(http_build_query($parameter)); $url = $url->withQuery(http_build_query($parameter));
return (string)$url; return (string)$url;
} }

View file

@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\Events\Service;
use TYPO3\CMS\Core\Core\SystemEnvironmentBuilder;
use TYPO3\CMS\Core\Http\ServerRequest;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
final class ExtbaseConfigurationManagerService
{
public function __construct(
private readonly ConfigurationManagerInterface $configurationManager
) {
}
/**
* The mapper uses queries, which rely an on the configuration manager.
* But import is without request, so we ensure it is properly initialized.
*
* This should vanish, see: Documentation/Maintenance.rst
*/
public function configureForBackend(): void
{
// TODO: typo3/cms-core:14.0 Remove condition as this method is provided since 13.
if (method_exists($this->configurationManager, 'setRequest') === false) {
return;
}
$request = new ServerRequest();
$request = $request->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_BE);
$this->configurationManager->setRequest($request);
}
public function getInstanceWithBackendContext(): ConfigurationManagerInterface
{
$this->configureForBackend();
return $this->configurationManager;
}
}

View file

@ -234,9 +234,8 @@ class MigrateOldLocations implements UpgradeWizardInterface
{ {
$schema = $this->connectionPool $schema = $this->connectionPool
->getConnectionForTable('tx_events_domain_model_event') ->getConnectionForTable('tx_events_domain_model_event')
->getSchemaManager() ->getSchemaInformation()
->createSchema() ->introspectTable('tx_events_domain_model_event')
->getTable('tx_events_domain_model_event')
; ;
foreach ($this->columnsToFetch() as $column) { foreach ($this->columnsToFetch() as $column) {

View file

@ -0,0 +1,59 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2024 Daniel Siepmann <daniel.siepmann@codappix.com>
*
* 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\Updates;
use TYPO3\CMS\Install\Attribute\UpgradeWizard;
use TYPO3\CMS\Install\Updates\AbstractListTypeToCTypeUpdate;
// TODO: typo3/cms-core:14.0 Remove condition as this class is provided since 13.
if (class_exists(AbstractListTypeToCTypeUpdate::class) === false) {
final class MigratePluginsFromListToCtype
{
}
return;
}
#[UpgradeWizard(MigratePluginsFromListToCtype::class)]
final class MigratePluginsFromListToCtype extends AbstractListTypeToCTypeUpdate
{
protected function getListTypeToCTypeMapping(): array
{
return [
'events_datelist' => 'events_datelist',
'events_datesearch' => 'events_datesearch',
'events_dateshow ' => 'events_dateshow',
'events_selected ' => 'events_selected',
];
}
public function getTitle(): string
{
return 'Migrate EXT:events content elements.';
}
public function getDescription(): string
{
return 'Migrate CType from list to dedicated plugins.';
}
}

View file

@ -2,127 +2,108 @@
<sheets> <sheets>
<sDEF> <sDEF>
<ROOT> <ROOT>
<TCEforms> <sheetTitle>Options</sheetTitle>
<sheetTitle>Options</sheetTitle>
</TCEforms>
<type>array</type> <type>array</type>
<el> <el>
<settings.sortByDate> <settings.sortByDate>
<TCEforms> <exclude>1</exclude>
<exclude>1</exclude> <label>Sort By</label>
<label>Sort By</label> <config>
<config> <type>select</type>
<type>select</type> <renderType>selectSingle</renderType>
<renderType>selectSingle</renderType> <items type="array">
<items type="array"> <numIndex index="0" type="array">
<numIndex index="0" type="array"> <numIndex index="label">Start</numIndex>
<numIndex index="0">Start</numIndex> <numIndex index="value">start</numIndex>
<numIndex index="1">start</numIndex> </numIndex>
</numIndex> <numIndex index="1" type="array">
<numIndex index="1" type="array"> <numIndex index="label">End</numIndex>
<numIndex index="0">End</numIndex> <numIndex index="value">end</numIndex>
<numIndex index="1">end</numIndex> </numIndex>
</numIndex> </items>
</items> </config>
</config>
</TCEforms>
</settings.sortByDate> </settings.sortByDate>
<settings.sortOrder> <settings.sortOrder>
<TCEforms> <exclude>1</exclude>
<exclude>1</exclude> <label>Sort Order</label>
<label>Sort Order</label> <config>
<config> <type>select</type>
<type>select</type> <renderType>selectSingle</renderType>
<renderType>selectSingle</renderType> <items type="array">
<items type="array"> <numIndex index="0" type="array">
<numIndex index="0" type="array"> <numIndex index="label">
<numIndex index="0"> Ascending
Ascending
</numIndex>
<numIndex index="1">ASC</numIndex>
</numIndex> </numIndex>
<numIndex index="1" type="array"> <numIndex index="value">ASC</numIndex>
<numIndex index="0"> </numIndex>
Descending <numIndex index="1" type="array">
</numIndex> <numIndex index="label">
<numIndex index="1">DESC</numIndex> Descending
</numIndex> </numIndex>
</items> <numIndex index="value">DESC</numIndex>
<default>ASC</default> </numIndex>
</config> </items>
</TCEforms> <default>ASC</default>
</config>
</settings.sortOrder> </settings.sortOrder>
<settings.limit> <settings.limit>
<TCEforms> <exclude>1</exclude>
<exclude>1</exclude> <label>Max Items</label>
<label>Max Items</label> <config>
<config> <type>input</type>
<type>input</type> <size>10</size>
<size>10</size> <max>30</max>
<max>30</max> <eval>trim</eval>
<eval>trim</eval> </config>
</config>
</TCEforms>
</settings.limit> </settings.limit>
<settings.highlight> <settings.highlight>
<TCEforms> <exclude>1</exclude>
<exclude>1</exclude> <label>Highlights only</label>
<label>Highlights only</label> <config>
<config> <type>check</type>
<type>check</type> <default>0</default>
<default>0</default> </config>
</config>
</TCEforms>
</settings.highlight> </settings.highlight>
<settings.todayOnly> <settings.todayOnly>
<TCEforms> <exclude>1</exclude>
<exclude>1</exclude> <label>Today only</label>
<label>Today only</label> <config>
<config> <type>check</type>
<type>check</type> <default>0</default>
<default>0</default> </config>
</config>
</TCEforms>
</settings.todayOnly> </settings.todayOnly>
<settings.pagination> <settings.pagination>
<TCEforms> <exclude>1</exclude>
<exclude>1</exclude> <label>Show pagination</label>
<label>Show pagination</label> <config>
<config> <type>check</type>
<type>check</type> <default>0</default>
<default>0</default> </config>
</config>
</TCEforms>
</settings.pagination> </settings.pagination>
<settings.showPID> <settings.showPID>
<TCEforms> <exclude>1</exclude>
<exclude>1</exclude> <label>Detail page</label>
<label>Detail page</label> <config>
<config> <type>group</type>
<type>group</type> <allowed>pages</allowed>
<internal_type>db</internal_type> <size>1</size>
<allowed>pages</allowed> <maxitems>1</maxitems>
<size>1</size> <minitems>0</minitems>
<maxitems>1</maxitems> <show_thumbs>1</show_thumbs>
<minitems>0</minitems> </config>
<show_thumbs>1</show_thumbs>
</config>
</TCEforms>
</settings.showPID> </settings.showPID>
</el> </el>
</ROOT> </ROOT>
</sDEF> </sDEF>
<sTemplate> <sTemplate>
<ROOT> <ROOT>
<TCEforms> <sheetTitle>Template</sheetTitle>
<sheetTitle>Template</sheetTitle>
</TCEforms>
<type>array</type> <type>array</type>
<el> <el>
<settings.template> <settings.template>
@ -133,20 +114,20 @@
<renderType>selectSingle</renderType> <renderType>selectSingle</renderType>
<items type="array"> <items type="array">
<numIndex index="0" type="array"> <numIndex index="0" type="array">
<numIndex index="0">Default</numIndex> <numIndex index="label">Default</numIndex>
<numIndex index="1">default</numIndex> <numIndex index="value">default</numIndex>
</numIndex> </numIndex>
<numIndex index="1" type="array"> <numIndex index="1" type="array">
<numIndex index="0">Costum</numIndex> <numIndex index="label">Custom</numIndex>
<numIndex index="1">costum</numIndex> <numIndex index="value">costum</numIndex>
</numIndex> </numIndex>
<numIndex index="2" type="array"> <numIndex index="2" type="array">
<numIndex index="0">Table</numIndex> <numIndex index="label">Table</numIndex>
<numIndex index="1">table</numIndex> <numIndex index="value">table</numIndex>
</numIndex> </numIndex>
<numIndex index="3" type="array"> <numIndex index="3" type="array">
<numIndex index="0">Grid</numIndex> <numIndex index="label">Grid</numIndex>
<numIndex index="1">grid</numIndex> <numIndex index="value">grid</numIndex>
</numIndex> </numIndex>
</items> </items>
<default>default</default> <default>default</default>
@ -157,34 +138,29 @@
</sTemplate> </sTemplate>
<sConstrains> <sConstrains>
<ROOT> <ROOT>
<TCEforms> <sheetTitle>Regions &amp; Categories</sheetTitle>
<sheetTitle>Regions &amp; Categories</sheetTitle>
</TCEforms>
<type>array</type> <type>array</type>
<el> <el>
<settings.region> <settings.region>
<TCEforms> <label>Region</label>
<label>Region</label> <config>
<config> <type>select</type>
<type>select</type> <renderType>selectSingle</renderType>
<renderType>selectSingle</renderType> <items type="array">
<items type="array"> <numIndex index="0" type="array">
<numIndex index="0" type="array"> <numIndex index="label">Alle</numIndex>
<numIndex index="0">Alle</numIndex> <numIndex index="value"></numIndex>
<numIndex index="1"></numIndex> </numIndex>
</numIndex> </items>
</items> <foreign_table>tx_events_domain_model_region</foreign_table>
<foreign_table>tx_events_domain_model_region</foreign_table> <foreign_table_where>AND tx_events_domain_model_region.deleted = 0 AND tx_events_domain_model_region.hidden = 0</foreign_table_where>
<foreign_table_where>AND tx_events_domain_model_region.deleted = 0 AND tx_events_domain_model_region.hidden = 0</foreign_table_where> <size>1</size>
<size>1</size> <minitems>0</minitems>
<minitems>0</minitems> <maxitems>1</maxitems>
<maxitems>1</maxitems> </config>
</config>
</TCEforms>
</settings.region> </settings.region>
<settings.categoryCombination> <settings.categoryCombination>
<TCEforms>
<exclude>1</exclude> <exclude>1</exclude>
<label>Combination</label> <label>Combination</label>
<config> <config>
@ -192,54 +168,49 @@
<renderType>selectSingle</renderType> <renderType>selectSingle</renderType>
<items type="array"> <items type="array">
<numIndex index="0" type="array"> <numIndex index="0" type="array">
<numIndex index="0">And</numIndex> <numIndex index="label">And</numIndex>
<numIndex index="1">0</numIndex> <numIndex index="value">0</numIndex>
</numIndex> </numIndex>
<numIndex index="1" type="array"> <numIndex index="1" type="array">
<numIndex index="0">Or</numIndex> <numIndex index="label">Or</numIndex>
<numIndex index="1">1</numIndex> <numIndex index="value">1</numIndex>
</numIndex> </numIndex>
</items> </items>
<default>0</default> <default>0</default>
</config> </config>
</TCEforms>
</settings.categoryCombination> </settings.categoryCombination>
<settings.categories> <settings.categories>
<TCEforms> <exclude>1</exclude>
<exclude>1</exclude> <label>
<label> Category
Category </label>
</label> <config>
<config> <type>select</type>
<type>select</type> <renderType>selectTree</renderType>
<renderType>selectTree</renderType> <autoSizeMax>20</autoSizeMax>
<autoSizeMax>20</autoSizeMax> <foreign_table>sys_category</foreign_table>
<foreign_table>sys_category</foreign_table> <foreign_table_where> AND sys_category.sys_language_uid IN (-1, 0) ORDER BY sys_category.title ASC</foreign_table_where>
<foreign_table_where> AND sys_category.sys_language_uid IN (-1, 0) ORDER BY sys_category.title ASC</foreign_table_where> <maxitems>1</maxitems>
<maxitems>1</maxitems> <renderMode>tree</renderMode>
<renderMode>tree</renderMode> <size>8</size>
<size>8</size> <treeConfig>
<treeConfig> <appearance>
<appearance> <expandAll>1</expandAll>
<expandAll>1</expandAll> <showHeader>1</showHeader>
<showHeader>1</showHeader> </appearance>
</appearance> <parentField>parent</parentField>
<parentField>parent</parentField> </treeConfig>
</treeConfig> </config>
</config>
</TCEforms>
</settings.categories> </settings.categories>
<settings.includeSubcategories> <settings.includeSubcategories>
<TCEforms>
<exclude>1</exclude> <exclude>1</exclude>
<label>Include Subcategories</label> <label>Include Subcategories</label>
<config> <config>
<type>check</type> <type>check</type>
<default>0</default> <default>0</default>
</config> </config>
</TCEforms>
</settings.includeSubcategories> </settings.includeSubcategories>
</el> </el>
</ROOT> </ROOT>

View file

@ -2,38 +2,31 @@
<sheets> <sheets>
<sSearch> <sSearch>
<ROOT> <ROOT>
<TCEforms> <sheetTitle>Options</sheetTitle>
<sheetTitle>Options</sheetTitle>
</TCEforms>
<type>array</type> <type>array</type>
<el> <el>
<settings.pageUid> <settings.pageUid>
<TCEforms> <exclude>1</exclude>
<exclude>1</exclude> <label>Results page</label>
<label>Results page</label> <config>
<config> <type>group</type>
<type>group</type> <allowed>pages</allowed>
<internal_type>db</internal_type> <size>1</size>
<allowed>pages</allowed> <maxitems>1</maxitems>
<size>1</size> <minitems>0</minitems>
<maxitems>1</maxitems> <show_thumbs>1</show_thumbs>
<minitems>0</minitems> </config>
<show_thumbs>1</show_thumbs>
</config>
</TCEforms>
</settings.pageUid> </settings.pageUid>
<settings.showRegions> <settings.showRegions>
<TCEforms> <exclude>1</exclude>
<exclude>1</exclude> <label>Show Regions</label>
<label>Show Regions</label> <config>
<config> <type>check</type>
<type>check</type> <default>0</default>
<default>0</default> </config>
</config>
</TCEforms>
</settings.showRegions> </settings.showRegions>
</el> </el>
</ROOT> </ROOT>
</sSearch> </sSearch>
</sheets> </sheets>
</T3DataStructure> </T3DataStructure>

View file

@ -2,34 +2,27 @@
<sheets> <sheets>
<sDEF> <sDEF>
<ROOT> <ROOT>
<TCEforms> <sheetTitle>Options</sheetTitle>
<sheetTitle>Options</sheetTitle>
</TCEforms>
<type>array</type> <type>array</type>
<el> <el>
<settings.backPID> <settings.backPID>
<TCEforms>
<exclude>1</exclude> <exclude>1</exclude>
<label>Back page</label> <label>Back page</label>
<config> <config>
<type>group</type> <type>group</type>
<internal_type>db</internal_type>
<allowed>pages</allowed> <allowed>pages</allowed>
<size>1</size> <size>1</size>
<maxitems>1</maxitems> <maxitems>1</maxitems>
<minitems>0</minitems> <minitems>0</minitems>
<show_thumbs>1</show_thumbs> <show_thumbs>1</show_thumbs>
</config> </config>
</TCEforms>
</settings.backPID> </settings.backPID>
</el> </el>
</ROOT> </ROOT>
</sDEF> </sDEF>
<sTemplate> <sTemplate>
<ROOT> <ROOT>
<TCEforms> <sheetTitle>Template</sheetTitle>
<sheetTitle>Template</sheetTitle>
</TCEforms>
<type>array</type> <type>array</type>
<el> <el>
<settings.template> <settings.template>
@ -39,12 +32,12 @@
<type>select</type> <type>select</type>
<items type="array"> <items type="array">
<numIndex index="0" type="array"> <numIndex index="0" type="array">
<numIndex index="0">Default</numIndex> <numIndex index="label">Default</numIndex>
<numIndex index="1">default</numIndex> <numIndex index="value">default</numIndex>
</numIndex> </numIndex>
<numIndex index="1" type="array"> <numIndex index="1" type="array">
<numIndex index="0">Costum</numIndex> <numIndex index="label">Custom</numIndex>
<numIndex index="1">costum</numIndex> <numIndex index="value">costum</numIndex>
</numIndex> </numIndex>
</items> </items>
<default>default</default> <default>default</default>
@ -54,4 +47,4 @@
</ROOT> </ROOT>
</sTemplate> </sTemplate>
</sheets> </sheets>
</T3DataStructure> </T3DataStructure>

View file

@ -5,17 +5,14 @@
<type>array</type> <type>array</type>
<el> <el>
<settings.selectedRecords> <settings.selectedRecords>
<TCEforms> <exclude>1</exclude>
<exclude>1</exclude> <label>LLL:EXT:events/Resources/Private/Language/de.locallang_db.xlf:tx_events.flexform.selected.selectedRecords</label>
<label>LLL:EXT:events/Resources/Private/Language/de.locallang_db.xlf:tx_events.flexform.selected.selectedRecords</label> <config>
<config> <type>group</type>
<type>group</type> <allowed>tx_events_domain_model_event</allowed>
<internal_type>db</internal_type> <minitems>1</minitems>
<allowed>tx_events_domain_model_event</allowed> <show_thumbs>1</show_thumbs>
<minitems>1</minitems> </config>
<show_thumbs>1</show_thumbs>
</config>
</TCEforms>
</settings.selectedRecords> </settings.selectedRecords>
</el> </el>
</ROOT> </ROOT>

16
Configuration/Icons.php Normal file
View file

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
use TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider;
return [
'events-plugin' => [
'provider' => SvgIconProvider::class,
'source' => 'EXT:events/Resources/Public/Icons/Extension.svg',
],
'pages-module-events' => [
'provider' => SvgIconProvider::class,
'source' => 'EXT:events/Resources/Public/Icons/Folder.svg',
],
];

View file

@ -43,7 +43,12 @@ services:
WerkraumMedia\Events\Updates\MigrateOldLocations: WerkraumMedia\Events\Updates\MigrateOldLocations:
public: true public: true
WerkraumMedia\Events\Service\DestinationDataImportService\ConfigurationServiceInterface:
alias: 'WerkraumMedia\Events\Service\DestinationDataImportService\ExtbaseConfigurationService'
WerkraumMedia\Events\Caching\PageCacheTimeout: WerkraumMedia\Events\Caching\PageCacheTimeout:
arguments:
'$runtimeCache': '@cache.runtime'
tags: tags:
- name: event.listener - name: event.listener
event: WerkraumMedia\Events\Events\Controller\DateListVariables event: WerkraumMedia\Events\Events\Controller\DateListVariables

View file

@ -7,54 +7,58 @@ use TYPO3\CMS\Extbase\Utility\ExtensionUtility;
(function (string $extKey, string $table) { (function (string $extKey, string $table) {
/* Search Plugin */ /* Search Plugin */
ExtensionUtility::registerPlugin( $pluginSignature = ExtensionUtility::registerPlugin(
'Events', 'Events',
'DateSearch', 'DateSearch',
'Events: Date Search', 'Events: Date Search',
'EXT:events/Resources/Public/Icons/Extension.svg' 'events-plugin'
); );
$GLOBALS['TCA'][$table]['types']['list']['subtypes_addlist']['events_datesearch'] = 'pi_flexform'; ExtensionManagementUtility::addToAllTCAtypes($table, 'pi_flexform', $pluginSignature, 'after:subheader');
ExtensionManagementUtility::addPiFlexFormValue( ExtensionManagementUtility::addPiFlexFormValue(
'events_datesearch', '*',
'FILE:EXT:events/Configuration/FlexForms/DateSearch.xml' 'FILE:EXT:events/Configuration/FlexForms/DateSearch.xml',
$pluginSignature,
); );
/* Date List Plugin */ /* Date List Plugin */
ExtensionUtility::registerPlugin( $pluginSignature = ExtensionUtility::registerPlugin(
'Events', 'Events',
'DateList', 'DateList',
'Events: Date List', 'Events: Date List',
'EXT:events/Resources/Public/Icons/Extension.svg' 'events-plugin'
); );
$GLOBALS['TCA'][$table]['types']['list']['subtypes_addlist']['events_datelist'] = 'pi_flexform'; ExtensionManagementUtility::addToAllTCAtypes($table, 'pi_flexform', $pluginSignature, 'after:subheader');
ExtensionManagementUtility::addPiFlexFormValue( ExtensionManagementUtility::addPiFlexFormValue(
'events_datelist', '*',
'FILE:EXT:events/Configuration/FlexForms/DateList.xml' 'FILE:EXT:events/Configuration/FlexForms/DateList.xml',
$pluginSignature,
); );
/* Date Show Plugin */ /* Date Show Plugin */
ExtensionUtility::registerPlugin( $pluginSignature = ExtensionUtility::registerPlugin(
'Events', 'Events',
'DateShow', 'DateShow',
'Events: Date Show', 'Events: Date Show',
'EXT:events/Resources/Public/Icons/Extension.svg' 'events-plugin'
); );
$GLOBALS['TCA'][$table]['types']['list']['subtypes_addlist']['events_dateshow'] = 'pi_flexform'; ExtensionManagementUtility::addToAllTCAtypes($table, 'pi_flexform', $pluginSignature, 'after:subheader');
ExtensionManagementUtility::addPiFlexFormValue( ExtensionManagementUtility::addPiFlexFormValue(
'*',
'FILE:EXT:events/Configuration/FlexForms/DateShow.xml',
'events_dateshow', 'events_dateshow',
'FILE:EXT:events/Configuration/FlexForms/DateShow.xml'
); );
/* Event Selected Plugin */ /* Event Selected Plugin */
ExtensionUtility::registerPlugin( $pluginSignature = ExtensionUtility::registerPlugin(
'Events', 'Events',
'Selected', 'Selected',
'Events: Show selected', 'Events: Show selected',
'EXT:events/Resources/Public/Icons/Extension.svg' 'events-plugin'
); );
$GLOBALS['TCA'][$table]['types']['list']['subtypes_addlist']['events_selected'] = 'pi_flexform'; ExtensionManagementUtility::addToAllTCAtypes($table, 'pi_flexform', $pluginSignature, 'after:subheader');
ExtensionManagementUtility::addPiFlexFormValue( ExtensionManagementUtility::addPiFlexFormValue(
$pluginSignature,
'FILE:EXT:events/Configuration/FlexForms/Selected.xml',
'events_selected', 'events_selected',
'FILE:EXT:events/Configuration/FlexForms/Selected.xml'
); );
})('events', 'tt_content'); })('events', 'tt_content');

View file

@ -346,7 +346,6 @@ return [
'config' => [ 'config' => [
'type' => 'category', 'type' => 'category',
'minitems' => 0, 'minitems' => 0,
'multiple' => true,
], ],
], ],
'features' => [ 'features' => [
@ -355,7 +354,6 @@ return [
'config' => [ 'config' => [
'type' => 'category', 'type' => 'category',
'minitems' => 0, 'minitems' => 0,
'multiple' => true,
], ],
], ],
'keywords' => [ 'keywords' => [
@ -409,6 +407,12 @@ return [
'default' => 0, 'default' => 0,
'minitems' => 0, 'minitems' => 0,
'maxitems' => 1, 'maxitems' => 1,
'items' => [
[
'value' => '0',
'label' => $l10nPath . ':tx_events_domain_model_event.location.0',
],
],
], ],
], ],
'organizer' => [ 'organizer' => [
@ -421,6 +425,12 @@ return [
'default' => 0, 'default' => 0,
'minitems' => 0, 'minitems' => 0,
'maxitems' => 1, 'maxitems' => 1,
'items' => [
[
'value' => '0',
'label' => $l10nPath . ':tx_events_domain_model_event.location.0',
],
],
], ],
], ],
'region' => [ 'region' => [
@ -433,6 +443,12 @@ return [
'default' => 0, 'default' => 0,
'minitems' => 0, 'minitems' => 0,
'maxitems' => 1, 'maxitems' => 1,
'items' => [
[
'value' => '0',
'label' => $l10nPath . ':tx_events_domain_model_event.location.0',
],
],
], ],
], ],

View file

@ -26,7 +26,7 @@ return [
'--palette--;;typo3_storage', '--palette--;;typo3_storage',
'--palette--;;categories', '--palette--;;categories',
'--palette--;;features', '--palette--;;features',
'-palette--;;relations', '--palette--;;relations',
'--div--;LLL:EXT:events/Resources/Private/Language/locallang_csh_import.xlf:tx_events_domain_model_import.div.rest', '--div--;LLL:EXT:events/Resources/Private/Language/locallang_csh_import.xlf:tx_events_domain_model_import.div.rest',
'rest_experience', 'rest_experience',
'rest_search_query', 'rest_search_query',

View file

@ -14,7 +14,7 @@ plugin.tx_events {
} }
settings { settings {
# cat=plugin.tx_events//a; type=string; label=Default Image # cat=plugin.tx_events//a; type=string; label=Default Image
defaultImagePath = typo3conf/ext/events/Resources/Public/Images/default.jpg defaultImagePath = EXT:events/Resources/Public/Images/default.jpg
destinationData { destinationData {
# cat=plugin.tx_events//a; type=string; label=Rest Url # cat=plugin.tx_events//a; type=string; label=Rest Url
restUrl = http://meta.et4.de/rest.ashx/search/ restUrl = http://meta.et4.de/rest.ashx/search/

View file

@ -0,0 +1,35 @@
5.0.0
=====
Breaking
--------
* Only when being on 13.x or higher:
Content elements are no longer registered as `list` but with their own CType.
An upgrade wizard is provided that can be executed to migrate existing database
entries.
But custom TypoScript and modifications need to be adopted.
We recommend not to use the provided plugins but build your own tailored content
elements instead.
Features
--------
* Add Support for TYPO3 v13.4 LTS.
Fixes
-----
Nothing
Tasks
-----
Nothing
Deprecation
-----------
Nothing

View file

@ -43,6 +43,8 @@ Table of Contents
Settings Settings
Changelog Changelog
Maintenance
.. toctree:: .. toctree::
:hidden: :hidden:

View file

@ -0,0 +1,16 @@
Maintenance
===========
Migrate to SiteSets
-------------------
We currently leverage TypoScript for some configuration during import.
This is a bad idea, TypoScript is not intended for this usage.
We should migrate to Site Sets in the future.
The import should use the page uid for import records to resolve the site and fetch
corresponding settings.
That way the import can provide all the necessary information and can be passed down
to all classes.

View file

@ -1,11 +0,0 @@
[general]
project = Events Extension
copyright = since 2019 by Dirk Koritnik and Daniel Siepmann
[html_theme_options]
github_branch = main
github_repository = werkraum-media/events
project_home = https://github.com/werkraum-media/events/
project_issues = https://github.com/werkraum-media/events/issues
project_repository = https://github.com/werkraum-media/events/

21
Documentation/guides.xml Normal file
View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<guides
xmlns="https://www.phpdoc.org/guides"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.phpdoc.org/guides ../vendor/phpdocumentor/guides-cli/resources/schema/guides.xsd"
links-are-relative="true"
>
<extension
class="\T3Docs\Typo3DocsTheme\DependencyInjection\Typo3DocsThemeExtension"
project-home="https://github.com/werkraum-media/events/"
project-repository="https://github.com/werkraum-media/events/"
project-issues="https://github.com/werkraum-media/events/issues"
edit-on-github-branch="main"
edit-on-github="werkraum-media/events"
typo3-core-preferred="stable"
/>
<project
title="Events Extension"
copyright="since 2019 by Dirk Koritnik and Daniel Siepmann"
/>
</guides>

View file

@ -123,14 +123,26 @@
<source>Location</source> <source>Location</source>
<target>Veranstaltungsort</target> <target>Veranstaltungsort</target>
</trans-unit> </trans-unit>
<trans-unit id="tx_events_domain_model_event.location.0">
<source>None</source>
<target>Keine</target>
</trans-unit>
<trans-unit id="tx_events_domain_model_event.organizer"> <trans-unit id="tx_events_domain_model_event.organizer">
<source>Organizer</source> <source>Organizer</source>
<target>Organisator</target> <target>Organisator</target>
</trans-unit> </trans-unit>
<trans-unit id="tx_events_domain_model_event.organizer.0">
<source>None</source>
<target>Keiner</target>
</trans-unit>
<trans-unit id="tx_events_domain_model_event.region"> <trans-unit id="tx_events_domain_model_event.region">
<source>Region</source> <source>Region</source>
<target>Region</target> <target>Region</target>
</trans-unit> </trans-unit>
<trans-unit id="tx_events_domain_model_event.region.0">
<source>None</source>
<target>Keine</target>
</trans-unit>
<trans-unit id="tx_events_domain_model_organizer"> <trans-unit id="tx_events_domain_model_organizer">
<source>Organizer</source> <source>Organizer</source>
<target>Organisator</target> <target>Organisator</target>

View file

@ -93,12 +93,21 @@
<trans-unit id="tx_events_domain_model_event.location"> <trans-unit id="tx_events_domain_model_event.location">
<source>Location</source> <source>Location</source>
</trans-unit> </trans-unit>
<trans-unit id="tx_events_domain_model_event.location.0">
<source>None</source>
</trans-unit>
<trans-unit id="tx_events_domain_model_event.organizer"> <trans-unit id="tx_events_domain_model_event.organizer">
<source>Organizer</source> <source>Organizer</source>
</trans-unit> </trans-unit>
<trans-unit id="tx_events_domain_model_event.organizer.0">
<source>None</source>
</trans-unit>
<trans-unit id="tx_events_domain_model_event.region"> <trans-unit id="tx_events_domain_model_event.region">
<source>Region</source> <source>Region</source>
</trans-unit> </trans-unit>
<trans-unit id="tx_events_domain_model_event.region.0">
<source>None</source>
</trans-unit>
<trans-unit id="tx_events_domain_model_event.partner"> <trans-unit id="tx_events_domain_model_event.partner">
<source>Partner</source> <source>Partner</source>
</trans-unit> </trans-unit>

View file

@ -149,6 +149,7 @@ abstract class AbstractFunctionalTestCase extends FunctionalTestCase
array $argumentsAndOptions = ['configurationUid' => '1'], array $argumentsAndOptions = ['configurationUid' => '1'],
string $command = ImportDestinationDataViaConfigruationCommand::class string $command = ImportDestinationDataViaConfigruationCommand::class
): CommandTester { ): CommandTester {
GeneralUtility::setContainer($this->getcontainer());
$subject = $this->get($command); $subject = $this->get($command);
self::assertInstanceOf(Command::class, $subject); self::assertInstanceOf(Command::class, $subject);

View file

@ -68,8 +68,7 @@ class CacheTest extends AbstractFunctionalTestCase
(new PhpDataSet())->import(['tt_content' => [[ (new PhpDataSet())->import(['tt_content' => [[
'uid' => '1', 'uid' => '1',
'pid' => '1', 'pid' => '1',
'CType' => 'list', 'CType' => 'events_datelisttest',
'list_type' => 'events_datelisttest',
'header' => 'All Dates', 'header' => 'All Dates',
]]]); ]]]);
$this->setUpFrontendRendering(); $this->setUpFrontendRendering();
@ -306,7 +305,7 @@ class CacheTest extends AbstractFunctionalTestCase
// We might be seconds off due to our created offset within the rendering. // We might be seconds off due to our created offset within the rendering.
$value = (int)$value; $value = (int)$value;
$age = ((int)$end->format('U')) - time(); $age = ((int)$end->format('U')) - time();
self::assertLessThanOrEqual($age + 3, $value, 'Max age of cached response is higher than expected.'); self::assertLessThanOrEqual($age + 4, $value, 'Max age of cached response is higher than expected.');
self::assertGreaterThanOrEqual($age - 3, $value, 'Max age of cached response is less than expected.'); self::assertGreaterThanOrEqual($age - 3, $value, 'Max age of cached response is less than expected.');
} }

View file

@ -7,8 +7,7 @@ return [
0 => [ 0 => [
'uid' => '1', 'uid' => '1',
'pid' => '1', 'pid' => '1',
'CType' => 'list', 'CType' => 'events_dateshow',
'list_type' => 'events_dateshow',
'header' => 'Singleview', 'header' => 'Singleview',
], ],
], ],

View file

@ -7,8 +7,7 @@ return [
0 => [ 0 => [
'uid' => '1', 'uid' => '1',
'pid' => '1', 'pid' => '1',
'CType' => 'list', 'CType' => 'events_dateshow',
'list_type' => 'events_dateshow',
'header' => 'Singleview', 'header' => 'Singleview',
], ],
], ],

View file

@ -7,8 +7,7 @@ return [
0 => [ 0 => [
'uid' => '1', 'uid' => '1',
'pid' => '1', 'pid' => '1',
'CType' => 'list', 'CType' => 'events_dateshow',
'list_type' => 'events_dateshow',
'header' => 'Singleview', 'header' => 'Singleview',
], ],
], ],

View file

@ -7,8 +7,7 @@ return [
0 => [ 0 => [
'uid' => '1', 'uid' => '1',
'pid' => '1', 'pid' => '1',
'CType' => 'list', 'CType' => 'events_dateshow',
'list_type' => 'events_dateshow',
'header' => 'Singleview', 'header' => 'Singleview',
], ],
], ],

View file

@ -7,8 +7,7 @@ return [
0 => [ 0 => [
'uid' => '1', 'uid' => '1',
'pid' => '1', 'pid' => '1',
'CType' => 'list', 'CType' => 'events_dateshow',
'list_type' => 'events_dateshow',
'header' => 'Singleview', 'header' => 'Singleview',
], ],
], ],

View file

@ -7,8 +7,7 @@ return [
0 => [ 0 => [
'uid' => '1', 'uid' => '1',
'pid' => '1', 'pid' => '1',
'CType' => 'list', 'CType' => 'events_datelist',
'list_type' => 'events_datelist',
'header' => 'All Dates', 'header' => 'All Dates',
], ],
], ],

View file

@ -7,8 +7,7 @@ return [
0 => [ 0 => [
'uid' => '1', 'uid' => '1',
'pid' => '1', 'pid' => '1',
'CType' => 'list', 'CType' => 'events_datelist',
'list_type' => 'events_datelist',
'header' => 'All Dates', 'header' => 'All Dates',
], ],
], ],

View file

@ -7,8 +7,7 @@ return [
[ [
'uid' => 1, 'uid' => 1,
'pid' => 1, 'pid' => 1,
'CType' => 'list', 'CType' => 'events_datelist',
'list_type' => 'events_datelist',
'header' => 'Upcoming Dates', 'header' => 'Upcoming Dates',
], ],
], ],

View file

@ -7,8 +7,7 @@ return [
0 => [ 0 => [
'uid' => '1', 'uid' => '1',
'pid' => '1', 'pid' => '1',
'CType' => 'list', 'CType' => 'events_eventshow',
'list_type' => 'events_eventshow',
'header' => 'Singleview', 'header' => 'Singleview',
], ],
], ],

View file

@ -7,8 +7,7 @@ return [
0 => [ 0 => [
'uid' => '1', 'uid' => '1',
'pid' => '1', 'pid' => '1',
'CType' => 'list', 'CType' => 'events_eventshow',
'list_type' => 'events_eventshow',
'header' => 'Singleview', 'header' => 'Singleview',
], ],
], ],

View file

@ -7,8 +7,7 @@ return [
0 => [ 0 => [
'uid' => '1', 'uid' => '1',
'pid' => '1', 'pid' => '1',
'CType' => 'list', 'CType' => 'events_eventshow',
'list_type' => 'events_eventshow',
'header' => 'Singleview', 'header' => 'Singleview',
], ],
], ],

View file

@ -7,8 +7,7 @@ return [
0 => [ 0 => [
'uid' => '1', 'uid' => '1',
'pid' => '1', 'pid' => '1',
'CType' => 'list', 'CType' => 'events_eventshow',
'list_type' => 'events_eventshow',
'header' => 'Singleview', 'header' => 'Singleview',
], ],
], ],

View file

@ -7,8 +7,7 @@ return [
[ [
'pid' => '1', 'pid' => '1',
'uid' => '1', 'uid' => '1',
'CType' => 'list', 'CType' => 'events_datelist',
'list_type' => 'events_datelist',
'header' => 'Kino Events', 'header' => 'Kino Events',
'pi_flexform' => '<?xml version="1.0" encoding="utf-8" standalone="yes" ?> 'pi_flexform' => '<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<T3FlexForms> <T3FlexForms>

View file

@ -7,8 +7,7 @@ return [
[ [
'pid' => '1', 'pid' => '1',
'uid' => '1', 'uid' => '1',
'CType' => 'list', 'CType' => 'events_datelist',
'list_type' => 'events_datelist',
'header' => 'Kino Events', 'header' => 'Kino Events',
'pi_flexform' => '<?xml version="1.0" encoding="utf-8" standalone="yes" ?> 'pi_flexform' => '<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<T3FlexForms> <T3FlexForms>

View file

@ -7,8 +7,7 @@ return [
[ [
'pid' => '1', 'pid' => '1',
'uid' => '1', 'uid' => '1',
'CType' => 'list', 'CType' => 'events_datelist',
'list_type' => 'events_datelist',
'header' => 'Kino Events', 'header' => 'Kino Events',
'pi_flexform' => '<?xml version="1.0" encoding="utf-8" standalone="yes" ?> 'pi_flexform' => '<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<T3FlexForms> <T3FlexForms>

View file

@ -23,6 +23,10 @@ declare(strict_types=1);
namespace WerkraumMedia\EventsExample; namespace WerkraumMedia\EventsExample;
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\Cache\CacheLifetimeCalculator;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController; use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
@ -35,9 +39,24 @@ final class UserFunc
$this->cObj = $cObj; $this->cObj = $cObj;
} }
public function accessTsfeTimeout(): string public function accessTsfeTimeout(string $content, array $configuration, ServerRequestInterface $request): string
{ {
return 'get_cache_timeout: ' . $this->getTsfe()->get_cache_timeout(); // TODO: typo3/cms-core:14.0 Remove this code block as this won't work since v13.x anymore
if (is_callable([$this->getTsfe(), 'get_cache_timeout'])) {
return 'get_cache_timeout: ' . $this->getTsfe()->get_cache_timeout();
}
$pageInformation = $request->getAttribute('frontend.page.information');
$typoScriptConfigArray = $request->getAttribute('frontend.typoscript')->getConfigArray();
return 'get_cache_timeout: ' . GeneralUtility::makeInstance(CacheLifetimeCalculator::class)
->calculateLifetimeForPage(
$pageInformation->getId(),
$pageInformation->getPageRecord(),
$typoScriptConfigArray,
0,
GeneralUtility::makeInstance(Context::class)
)
;
} }
public function sleep(string $content, array $configuration): string public function sleep(string $content, array $configuration): string

View file

@ -9,11 +9,15 @@ use WerkraumMedia\Events\Controller\EventController;
ExtensionUtility::configurePlugin( ExtensionUtility::configurePlugin(
'Events', 'Events',
'DateListTest', 'DateListTest',
[DateController::class => 'list'] [DateController::class => 'list'],
[],
ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT,
); );
ExtensionUtility::configurePlugin( ExtensionUtility::configurePlugin(
'Events', 'Events',
'EventShow', 'EventShow',
[EventController::class => 'show'] [EventController::class => 'show'],
[],
ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT,
); );

View file

@ -11,6 +11,7 @@ return [
'storage_pid' => '2', 'storage_pid' => '2',
'features_pid' => '3', 'features_pid' => '3',
'features_parent' => '4', 'features_parent' => '4',
'files_folder' => '1:/staedte/beispielstadt/events/',
], ],
], ],
'pages' => [ 'pages' => [

View file

@ -9,6 +9,7 @@ return [
'pid' => '2', 'pid' => '2',
'title' => 'Example for test', 'title' => 'Example for test',
'storage_pid' => '2', 'storage_pid' => '2',
'files_folder' => '1:/staedte/beispielstadt/events/',
], ],
], ],
'pages' => [ 'pages' => [

View file

@ -10,6 +10,7 @@ return [
'title' => 'Example import configuration', 'title' => 'Example import configuration',
'storage_pid' => '2', 'storage_pid' => '2',
'rest_experience' => 'beispielstadt', 'rest_experience' => 'beispielstadt',
'files_folder' => '1:/staedte/beispielstadt/events/',
], ],
], ],
]; ];

View file

@ -37,7 +37,7 @@ class DateDemandFactoryTest extends TestCase
#[Test] #[Test]
public function canBeCreated(): void public function canBeCreated(): void
{ {
$typoScriptService = $this->createStub(TypoScriptService::class); $typoScriptService = self::createStub(TypoScriptService::class);
$subject = new DateDemandFactory( $subject = new DateDemandFactory(
$typoScriptService $typoScriptService
@ -52,7 +52,7 @@ class DateDemandFactoryTest extends TestCase
#[Test] #[Test]
public function fromSettingsDoesNotThrowUndefinedArrayKeyWarnings(): void public function fromSettingsDoesNotThrowUndefinedArrayKeyWarnings(): void
{ {
$typoScriptService = $this->createStub(TypoScriptService::class); $typoScriptService = self::createStub(TypoScriptService::class);
$subject = new DateDemandFactory( $subject = new DateDemandFactory(
$typoScriptService $typoScriptService
@ -69,7 +69,7 @@ class DateDemandFactoryTest extends TestCase
#[Test] #[Test]
public function searchWordIsSetByRequest(): void public function searchWordIsSetByRequest(): void
{ {
$typoScriptService = $this->createStub(TypoScriptService::class); $typoScriptService = self::createStub(TypoScriptService::class);
$subject = new DateDemandFactory( $subject = new DateDemandFactory(
$typoScriptService $typoScriptService
@ -91,7 +91,7 @@ class DateDemandFactoryTest extends TestCase
#[Test] #[Test]
public function synonymsAreSetBySettings(): void public function synonymsAreSetBySettings(): void
{ {
$typoScriptService = $this->createStub(TypoScriptService::class); $typoScriptService = self::createStub(TypoScriptService::class);
$subject = new DateDemandFactory( $subject = new DateDemandFactory(
$typoScriptService $typoScriptService
@ -130,7 +130,7 @@ class DateDemandFactoryTest extends TestCase
#[Test] #[Test]
public function categoriesAreSetByRequest(): void public function categoriesAreSetByRequest(): void
{ {
$typoScriptService = $this->createStub(TypoScriptService::class); $typoScriptService = self::createStub(TypoScriptService::class);
$subject = new DateDemandFactory( $subject = new DateDemandFactory(
$typoScriptService $typoScriptService
@ -157,7 +157,7 @@ class DateDemandFactoryTest extends TestCase
#[Test] #[Test]
public function featuresAreSetByRequest(): void public function featuresAreSetByRequest(): void
{ {
$typoScriptService = $this->createStub(TypoScriptService::class); $typoScriptService = self::createStub(TypoScriptService::class);
$subject = new DateDemandFactory( $subject = new DateDemandFactory(
$typoScriptService $typoScriptService
@ -184,7 +184,7 @@ class DateDemandFactoryTest extends TestCase
#[Test] #[Test]
public function regionIsSetByRequest(): void public function regionIsSetByRequest(): void
{ {
$typoScriptService = $this->createStub(TypoScriptService::class); $typoScriptService = self::createStub(TypoScriptService::class);
$subject = new DateDemandFactory( $subject = new DateDemandFactory(
$typoScriptService $typoScriptService
@ -212,7 +212,7 @@ class DateDemandFactoryTest extends TestCase
#[Test] #[Test]
public function regionsAreSetByRequest(): void public function regionsAreSetByRequest(): void
{ {
$typoScriptService = $this->createStub(TypoScriptService::class); $typoScriptService = self::createStub(TypoScriptService::class);
$subject = new DateDemandFactory( $subject = new DateDemandFactory(
$typoScriptService $typoScriptService
@ -243,7 +243,7 @@ class DateDemandFactoryTest extends TestCase
#[Test] #[Test]
public function startIsSetByRequest(): void public function startIsSetByRequest(): void
{ {
$typoScriptService = $this->createStub(TypoScriptService::class); $typoScriptService = self::createStub(TypoScriptService::class);
$subject = new DateDemandFactory( $subject = new DateDemandFactory(
$typoScriptService $typoScriptService
@ -273,7 +273,7 @@ class DateDemandFactoryTest extends TestCase
#[Test] #[Test]
public function endIsSetByRequest(): void public function endIsSetByRequest(): void
{ {
$typoScriptService = $this->createStub(TypoScriptService::class); $typoScriptService = self::createStub(TypoScriptService::class);
$subject = new DateDemandFactory( $subject = new DateDemandFactory(
$typoScriptService $typoScriptService
@ -306,7 +306,7 @@ class DateDemandFactoryTest extends TestCase
string $start, string $start,
string $end string $end
): void { ): void {
$typoScriptService = $this->createStub(TypoScriptService::class); $typoScriptService = self::createStub(TypoScriptService::class);
$subject = new DateDemandFactory( $subject = new DateDemandFactory(
$typoScriptService $typoScriptService
@ -344,7 +344,7 @@ class DateDemandFactoryTest extends TestCase
#[Test] #[Test]
public function returnsEndsOnSameDayIfBothAreOnSameDay(): void public function returnsEndsOnSameDayIfBothAreOnSameDay(): void
{ {
$typoScriptService = $this->createStub(TypoScriptService::class); $typoScriptService = self::createStub(TypoScriptService::class);
$subject = new DateDemandFactory( $subject = new DateDemandFactory(
$typoScriptService $typoScriptService
@ -366,7 +366,7 @@ class DateDemandFactoryTest extends TestCase
#[Test] #[Test]
public function returnsEndsOnSameDayIfBothAreOnDifferentDays(): void public function returnsEndsOnSameDayIfBothAreOnDifferentDays(): void
{ {
$typoScriptService = $this->createStub(TypoScriptService::class); $typoScriptService = self::createStub(TypoScriptService::class);
$subject = new DateDemandFactory( $subject = new DateDemandFactory(
$typoScriptService $typoScriptService
@ -389,7 +389,7 @@ class DateDemandFactoryTest extends TestCase
#[Test] #[Test]
public function returnsHighlightIfSet(mixed $highlight): void public function returnsHighlightIfSet(mixed $highlight): void
{ {
$typoScriptService = $this->createStub(TypoScriptService::class); $typoScriptService = self::createStub(TypoScriptService::class);
$subject = new DateDemandFactory( $subject = new DateDemandFactory(
$typoScriptService $typoScriptService
@ -416,7 +416,7 @@ class DateDemandFactoryTest extends TestCase
#[Test] #[Test]
public function returnsNoHighlightIfNotSet(mixed $highlight): void public function returnsNoHighlightIfNotSet(mixed $highlight): void
{ {
$typoScriptService = $this->createStub(TypoScriptService::class); $typoScriptService = self::createStub(TypoScriptService::class);
$subject = new DateDemandFactory( $subject = new DateDemandFactory(
$typoScriptService $typoScriptService
@ -443,7 +443,7 @@ class DateDemandFactoryTest extends TestCase
#[Test] #[Test]
public function returnsOrganizersFromSettings(): void public function returnsOrganizersFromSettings(): void
{ {
$typoScriptService = $this->createStub(TypoScriptService::class); $typoScriptService = self::createStub(TypoScriptService::class);
$subject = new DateDemandFactory( $subject = new DateDemandFactory(
$typoScriptService $typoScriptService
@ -458,7 +458,7 @@ class DateDemandFactoryTest extends TestCase
#[Test] #[Test]
public function returnsOrganizersFromRequest(): void public function returnsOrganizersFromRequest(): void
{ {
$typoScriptService = $this->createStub(TypoScriptService::class); $typoScriptService = self::createStub(TypoScriptService::class);
$subject = new DateDemandFactory( $subject = new DateDemandFactory(
$typoScriptService $typoScriptService

View file

@ -26,9 +26,9 @@ class EventTest extends TestCase
#[Test] #[Test]
public function returnsSortedFeatures(): void public function returnsSortedFeatures(): void
{ {
$feature1 = $this->createStub(Category::class); $feature1 = self::createStub(Category::class);
$feature1->method('getSorting')->willReturn(10); $feature1->method('getSorting')->willReturn(10);
$feature2 = $this->createStub(Category::class); $feature2 = self::createStub(Category::class);
$feature2->method('getSorting')->willReturn(5); $feature2->method('getSorting')->willReturn(5);
$storage = new ObjectStorage(); $storage = new ObjectStorage();

View file

@ -16,7 +16,7 @@ class ImportTest extends TestCase
#[Test] #[Test]
public function canBeCreated(): void public function canBeCreated(): void
{ {
$folder = $this->createStub(Folder::class); $folder = self::createStub(Folder::class);
$subject = new Import( $subject = new Import(
$folder, $folder,
@ -33,7 +33,7 @@ class ImportTest extends TestCase
#[Test] #[Test]
public function returnsRestExperience(): void public function returnsRestExperience(): void
{ {
$folder = $this->createStub(Folder::class); $folder = self::createStub(Folder::class);
$subject = new Import( $subject = new Import(
$folder, $folder,
@ -50,7 +50,7 @@ class ImportTest extends TestCase
#[Test] #[Test]
public function returnsStoragePid(): void public function returnsStoragePid(): void
{ {
$folder = $this->createStub(Folder::class); $folder = self::createStub(Folder::class);
$subject = new Import( $subject = new Import(
$folder, $folder,
@ -67,8 +67,8 @@ class ImportTest extends TestCase
#[Test] #[Test]
public function returnsRegion(): void public function returnsRegion(): void
{ {
$folder = $this->createStub(Folder::class); $folder = self::createStub(Folder::class);
$region = $this->createStub(Region::class); $region = self::createStub(Region::class);
$subject = new Import( $subject = new Import(
$folder, $folder,
@ -91,7 +91,7 @@ class ImportTest extends TestCase
#[Test] #[Test]
public function returnsFilesFolder(): void public function returnsFilesFolder(): void
{ {
$folder = $this->createStub(Folder::class); $folder = self::createStub(Folder::class);
$subject = new Import( $subject = new Import(
$folder, $folder,
@ -108,7 +108,7 @@ class ImportTest extends TestCase
#[Test] #[Test]
public function returnsCategoriesPid(): void public function returnsCategoriesPid(): void
{ {
$folder = $this->createStub(Folder::class); $folder = self::createStub(Folder::class);
$subject = new Import( $subject = new Import(
$folder, $folder,
@ -127,8 +127,8 @@ class ImportTest extends TestCase
#[Test] #[Test]
public function returnsCategoryParent(): void public function returnsCategoryParent(): void
{ {
$category = $this->createStub(Category::class); $category = self::createStub(Category::class);
$folder = $this->createStub(Folder::class); $folder = self::createStub(Folder::class);
$subject = new Import( $subject = new Import(
$folder, $folder,
@ -148,7 +148,7 @@ class ImportTest extends TestCase
#[Test] #[Test]
public function returnsFeaturesPid(): void public function returnsFeaturesPid(): void
{ {
$folder = $this->createStub(Folder::class); $folder = self::createStub(Folder::class);
$subject = new Import( $subject = new Import(
$folder, $folder,
@ -169,8 +169,8 @@ class ImportTest extends TestCase
#[Test] #[Test]
public function returnsFeaturesParent(): void public function returnsFeaturesParent(): void
{ {
$feature = $this->createStub(Category::class); $feature = self::createStub(Category::class);
$folder = $this->createStub(Folder::class); $folder = self::createStub(Folder::class);
$subject = new Import( $subject = new Import(
$folder, $folder,
@ -192,7 +192,7 @@ class ImportTest extends TestCase
#[Test] #[Test]
public function returnsSearchQuery(): void public function returnsSearchQuery(): void
{ {
$folder = $this->createStub(Folder::class); $folder = self::createStub(Folder::class);
$subject = new Import( $subject = new Import(
$folder, $folder,

View file

@ -19,8 +19,8 @@ class DateListVariablesTest extends TestCase
$subject = new DateListVariables( $subject = new DateListVariables(
[], [],
new DateDemand(), new DateDemand(),
$this->createStub(QueryResult::class), self::createStub(QueryResult::class),
$this->createStub(PaginationInterface::class) self::createStub(PaginationInterface::class)
); );
self::assertInstanceOf( self::assertInstanceOf(
@ -37,8 +37,8 @@ class DateListVariablesTest extends TestCase
'executed' => '1', 'executed' => '1',
], ],
new DateDemand(), new DateDemand(),
$this->createStub(QueryResult::class), self::createStub(QueryResult::class),
$this->createStub(PaginationInterface::class) self::createStub(PaginationInterface::class)
); );
self::assertSame( self::assertSame(
@ -57,8 +57,8 @@ class DateListVariablesTest extends TestCase
[ [
], ],
$demand, $demand,
$this->createStub(QueryResult::class), self::createStub(QueryResult::class),
$this->createStub(PaginationInterface::class) self::createStub(PaginationInterface::class)
); );
self::assertSame( self::assertSame(
@ -70,13 +70,13 @@ class DateListVariablesTest extends TestCase
#[Test] #[Test]
public function returnsInitialDates(): void public function returnsInitialDates(): void
{ {
$dates = $this->createStub(QueryResult::class); $dates = self::createStub(QueryResult::class);
$subject = new DateListVariables( $subject = new DateListVariables(
[ [
], ],
new DateDemand(), new DateDemand(),
$dates, $dates,
$this->createStub(PaginationInterface::class) self::createStub(PaginationInterface::class)
); );
self::assertSame( self::assertSame(
@ -89,8 +89,8 @@ class DateListVariablesTest extends TestCase
public function returnsInitialVariablesForView(): void public function returnsInitialVariablesForView(): void
{ {
$demand = new DateDemand(); $demand = new DateDemand();
$dates = $this->createStub(QueryResult::class); $dates = self::createStub(QueryResult::class);
$pagination = $this->createStub(PaginationInterface::class); $pagination = self::createStub(PaginationInterface::class);
$subject = new DateListVariables( $subject = new DateListVariables(
[ [
'executed' => '1', 'executed' => '1',
@ -117,8 +117,8 @@ class DateListVariablesTest extends TestCase
public function returnsVariablesForViewWithAddedVariables(): void public function returnsVariablesForViewWithAddedVariables(): void
{ {
$demand = new DateDemand(); $demand = new DateDemand();
$dates = $this->createStub(QueryResult::class); $dates = self::createStub(QueryResult::class);
$pagination = $this->createStub(PaginationInterface::class); $pagination = self::createStub(PaginationInterface::class);
$subject = new DateListVariables( $subject = new DateListVariables(
[ [
'executed' => '1', 'executed' => '1',
@ -150,8 +150,8 @@ class DateListVariablesTest extends TestCase
public function returnsVariablesForViewWithOverwrittenVariables(): void public function returnsVariablesForViewWithOverwrittenVariables(): void
{ {
$demand = new DateDemand(); $demand = new DateDemand();
$dates = $this->createStub(QueryResult::class); $dates = self::createStub(QueryResult::class);
$pagination = $this->createStub(PaginationInterface::class); $pagination = self::createStub(PaginationInterface::class);
$subject = new DateListVariables( $subject = new DateListVariables(
[ [
'executed' => '1', 'executed' => '1',

View file

@ -21,7 +21,7 @@ class DateSearchVariablesTest extends TestCase
[ [
], ],
new DateDemand(), new DateDemand(),
$this->createStub(QueryResult::class), self::createStub(QueryResult::class),
[], [],
[] []
); );
@ -42,7 +42,7 @@ class DateSearchVariablesTest extends TestCase
[ [
], ],
new DateDemand(), new DateDemand(),
$this->createStub(QueryResult::class), self::createStub(QueryResult::class),
[], [],
[] []
); );
@ -65,7 +65,7 @@ class DateSearchVariablesTest extends TestCase
'executed' => '1', 'executed' => '1',
], ],
new DateDemand(), new DateDemand(),
$this->createStub(QueryResult::class), self::createStub(QueryResult::class),
[], [],
[] []
); );
@ -88,7 +88,7 @@ class DateSearchVariablesTest extends TestCase
[ [
], ],
$demand, $demand,
$this->createStub(QueryResult::class), self::createStub(QueryResult::class),
[], [],
[] []
); );
@ -102,7 +102,7 @@ class DateSearchVariablesTest extends TestCase
#[Test] #[Test]
public function returnsInitialRegions(): void public function returnsInitialRegions(): void
{ {
$regions = $this->createStub(QueryResult::class); $regions = self::createStub(QueryResult::class);
$subject = new DateSearchVariables( $subject = new DateSearchVariables(
[ [
], ],
@ -129,7 +129,7 @@ class DateSearchVariablesTest extends TestCase
[ [
], ],
new DateDemand(), new DateDemand(),
$this->createStub(QueryResult::class), self::createStub(QueryResult::class),
[ [
['example category'], ['example category'],
], ],
@ -153,7 +153,7 @@ class DateSearchVariablesTest extends TestCase
[ [
], ],
new DateDemand(), new DateDemand(),
$this->createStub(QueryResult::class), self::createStub(QueryResult::class),
[ [
], ],
[ [
@ -173,7 +173,7 @@ class DateSearchVariablesTest extends TestCase
public function returnsInitialVariablesForView(): void public function returnsInitialVariablesForView(): void
{ {
$demand = new DateDemand(); $demand = new DateDemand();
$regions = $this->createStub(QueryResult::class); $regions = self::createStub(QueryResult::class);
$subject = new DateSearchVariables( $subject = new DateSearchVariables(
[ [
], ],
@ -212,7 +212,7 @@ class DateSearchVariablesTest extends TestCase
public function returnsVariablesForViewWithAddedVariables(): void public function returnsVariablesForViewWithAddedVariables(): void
{ {
$demand = new DateDemand(); $demand = new DateDemand();
$regions = $this->createStub(QueryResult::class); $regions = self::createStub(QueryResult::class);
$subject = new DateSearchVariables( $subject = new DateSearchVariables(
[ [
], ],
@ -256,7 +256,7 @@ class DateSearchVariablesTest extends TestCase
public function returnsVariablesForViewWithOverwrittenVariables(): void public function returnsVariablesForViewWithOverwrittenVariables(): void
{ {
$demand = new DateDemand(); $demand = new DateDemand();
$regions = $this->createStub(QueryResult::class); $regions = self::createStub(QueryResult::class);
$subject = new DateSearchVariables( $subject = new DateSearchVariables(
[ [
], ],

View file

@ -22,13 +22,13 @@ class DatesFactoryTest extends TestCase
private function createTestSubject( private function createTestSubject(
string $contextDate string $contextDate
): DatesFactory { ): DatesFactory {
$logger = $this->createStub(Logger::class); $logger = self::createStub(Logger::class);
$logManager = $this->createStub(LogManager::class); $logManager = self::createStub(LogManager::class);
$logManager->method('getLogger')->willReturn($logger); $logManager->method('getLogger')->willReturn($logger);
return new DatesFactory( return new DatesFactory(
$this->createContext(new DateTimeImmutable($contextDate)), $this->createContext(new DateTimeImmutable($contextDate)),
$this->createStub(ConfigurationManager::class), self::createStub(ConfigurationManager::class),
$logManager $logManager
); );
} }

View file

@ -42,7 +42,7 @@ final class LocationAssignmentTest extends TestCase
#[Test] #[Test]
public function canBeCreated(): void public function canBeCreated(): void
{ {
$repository = $this->createStub(LocationRepository::class); $repository = self::createStub(LocationRepository::class);
$subject = new LocationAssignment( $subject = new LocationAssignment(
$repository $repository
); );
@ -63,7 +63,7 @@ final class LocationAssignmentTest extends TestCase
$latitude, $latitude,
$longitude $longitude
): void { ): void {
$repository = $this->createStub(LocationRepository::class); $repository = self::createStub(LocationRepository::class);
$repository->method('findOneByGlobalId')->willReturn(null); $repository->method('findOneByGlobalId')->willReturn(null);
$subject = new LocationAssignment( $subject = new LocationAssignment(

View file

@ -8,8 +8,8 @@ use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\Stub; use PHPUnit\Framework\MockObject\Stub;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager;
use WerkraumMedia\Events\Domain\Model\Import; use WerkraumMedia\Events\Domain\Model\Import;
use WerkraumMedia\Events\Service\DestinationDataImportService\ArrayBasedConfigurationService;
use WerkraumMedia\Events\Service\DestinationDataImportService\UrlFactory; use WerkraumMedia\Events\Service\DestinationDataImportService\UrlFactory;
class UrlFactoryTest extends TestCase class UrlFactoryTest extends TestCase
@ -17,8 +17,7 @@ class UrlFactoryTest extends TestCase
#[Test] #[Test]
public function canBeCreated(): void public function canBeCreated(): void
{ {
$configurationManager = $this->createStub(BackendConfigurationManager::class); $configurationManager = new ArrayBasedConfigurationService([]);
$configurationManager->method('getConfiguration')->willReturn([]);
$subject = new UrlFactory( $subject = new UrlFactory(
$configurationManager $configurationManager
@ -37,8 +36,7 @@ class UrlFactoryTest extends TestCase
array $settings, array $settings,
string $expectedResult string $expectedResult
): void { ): void {
$configurationManager = $this->createStub(BackendConfigurationManager::class); $configurationManager = new ArrayBasedConfigurationService($settings);
$configurationManager->method('getConfiguration')->willReturn(['settings' => ['destinationData' => $settings]]);
$subject = new UrlFactory( $subject = new UrlFactory(
$configurationManager $configurationManager

View file

@ -21,14 +21,14 @@
"require": { "require": {
"php": "~8.1.0 || ~8.2.0 || ~8.3.0", "php": "~8.1.0 || ~8.2.0 || ~8.3.0",
"symfony/console": "^6.4 || ^7.0", "symfony/console": "^6.4 || ^7.0",
"symfony/dependency-injection": "^6.4 || ^7.0", "symfony/dependency-injection": "^6.4 || ^7.0 || ^7.1",
"typo3/cms-core": "^12.4", "typo3/cms-core": "^12.4 || ^13.4",
"typo3/cms-extbase": "^12.4", "typo3/cms-extbase": "^12.4 || ^13.4",
"typo3/cms-filelist": "^12.4", "typo3/cms-filelist": "^12.4 || ^13.4",
"typo3/cms-filemetadata": "^12.4", "typo3/cms-filemetadata": "^12.4 || ^13.4",
"typo3/cms-fluid": "^12.4", "typo3/cms-fluid": "^12.4 || ^13.4",
"typo3/cms-frontend": "^12.4", "typo3/cms-frontend": "^12.4 || ^13.4",
"typo3/cms-install": "^12.4" "typo3/cms-install": "^12.4 || ^13.4"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
@ -69,10 +69,11 @@
"phpstan/extension-installer": "^1.1", "phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.10", "phpstan/phpstan": "^1.10",
"phpstan/phpstan-phpunit": "1.3.15", "phpstan/phpstan-phpunit": "1.3.15",
"saschaegerer/phpstan-typo3": "1.9.0", "saschaegerer/phpstan-typo3": "^1.10",
"typo3/cms-backend": "^12.4", "staabm/phpstan-todo-by": "^0.1.28",
"typo3/cms-fluid-styled-content": "^12.4", "typo3/cms-backend": "^12.4 || ^13.4",
"typo3/cms-seo": "^12.4", "typo3/cms-fluid-styled-content": "^12.4 || ^13.4",
"typo3/cms-seo": "^12.4 || ^13.4",
"typo3/testing-framework": "^8.0" "typo3/testing-framework": "^8.0"
}, },
"config": { "config": {

View file

@ -9,7 +9,7 @@ $EM_CONF['events'] = [
'author' => 'Dirk Koritnik, Daniel Siepmann', 'author' => 'Dirk Koritnik, Daniel Siepmann',
'author_email' => 'koritnik@werkraum-media.de, coding@daniel-siepmann.de', 'author_email' => 'koritnik@werkraum-media.de, coding@daniel-siepmann.de',
'state' => 'stable', 'state' => 'stable',
'version' => '4.2.1', 'version' => '5.0.0',
'constraints' => [ 'constraints' => [
'depends' => [ 'depends' => [
'typo3' => '', 'typo3' => '',

View file

@ -2,9 +2,6 @@
declare(strict_types=1); declare(strict_types=1);
use TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider;
use TYPO3\CMS\Core\Imaging\IconRegistry;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Utility\ExtensionUtility; use TYPO3\CMS\Extbase\Utility\ExtensionUtility;
use WerkraumMedia\Events\Controller\DateController; use WerkraumMedia\Events\Controller\DateController;
use WerkraumMedia\Events\Controller\EventController; use WerkraumMedia\Events\Controller\EventController;
@ -16,27 +13,32 @@ call_user_func(function () {
'Events', 'Events',
'DateSearch', 'DateSearch',
[DateController::class => 'search'], [DateController::class => 'search'],
[DateController::class => 'search'] [DateController::class => 'search'],
ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT
); );
ExtensionUtility::configurePlugin( ExtensionUtility::configurePlugin(
'Events', 'Events',
'DateList', 'DateList',
[DateController::class => 'list'], [DateController::class => 'list'],
[DateController::class => 'list'] [DateController::class => 'list'],
ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT
); );
ExtensionUtility::configurePlugin( ExtensionUtility::configurePlugin(
'Events', 'Events',
'DateShow', 'DateShow',
[DateController::class => 'show'], [DateController::class => 'show'],
[DateController::class => 'show'] [DateController::class => 'show'],
ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT
); );
ExtensionUtility::configurePlugin( ExtensionUtility::configurePlugin(
'Events', 'Events',
'Selected', 'Selected',
[EventController::class => 'list'] [EventController::class => 'list'],
[],
ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT
); );
if ( if (
@ -47,16 +49,4 @@ call_user_func(function () {
} }
$GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludedParameters'][] = '^events_search'; $GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludedParameters'][] = '^events_search';
$iconRegistry = GeneralUtility::makeInstance(IconRegistry::class);
$iconRegistry->registerIcon(
'events-plugin',
SvgIconProvider::class,
['source' => 'EXT:events/Resources/Public/Icons/Extension.svg']
);
$iconRegistry->registerIcon(
'pages-module-events',
SvgIconProvider::class,
['source' => 'EXT:events/Resources/Public/Icons/Folder.svg']
);
}); });

View file

@ -6,13 +6,8 @@ parameters:
path: Classes/Controller/DateController.php path: Classes/Controller/DateController.php
- -
message: "#^Parameter \\#1 \\$callback of function array_map expects \\(callable\\(mixed\\)\\: mixed\\)\\|null, 'strval' given\\.$#" message: "#^Parameter \\#1 \\$callback of function array_map expects \\(callable\\(mixed\\)\\: mixed\\)\\|null, Closure\\(bool\\|float\\|int\\|resource\\|string\\|null\\)\\: string given\\.$#"
count: 1 count: 2
path: Classes/Domain/DestinationData/ImportFactory.php
-
message: "#^Parameter \\#2 \\$array of function array_map expects array, mixed given\\.$#"
count: 1
path: Classes/Domain/DestinationData/ImportFactory.php path: Classes/Domain/DestinationData/ImportFactory.php
- -