diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..578dc10 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,10 @@ +codeception.dist.yml export-ignore +.gitattributes export-ignore +.github export-ignore +.gitignore export-ignore +.php-cs-fixer.dist.php export-ignore +phpstan-baseline.neon export-ignore +phpstan.neon export-ignore +phpunit.xml.dist export-ignore +shell.nix export-ignore +Tests export-ignore diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3f85f7b..2ade17b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -15,10 +15,9 @@ jobs: strategy: matrix: php-version: - - 7.4 - - 8.0 - 8.1 - 8.2 + - 8.3 steps: - name: Checkout uses: actions/checkout@v3 @@ -41,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 @@ -70,14 +69,14 @@ jobs: - name: Install PHP uses: shivammathur/setup-php@v2 with: - php-version: "7.4" + 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/ecs check + run: ./vendor/bin/php-cs-fixer fix --dry-run --diff code-quality: runs-on: ubuntu-latest @@ -86,16 +85,12 @@ jobs: strategy: matrix: include: - - 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 @@ -121,23 +116,14 @@ jobs: strategy: matrix: include: - - php-version: '7.4' - typo3-version: '^10.4' - db-version: '5.6' - - php-version: '7.4' - typo3-version: '^10.4' - db-version: '8' - - php-version: '7.4' - typo3-version: '^11.5' - db-version: '8' - - php-version: '8.0' - typo3-version: '^11.5' - db-version: '8' - php-version: '8.1' - typo3-version: '^11.5' + typo3-version: '^12.4' db-version: '8' - php-version: '8.2' - typo3-version: '^11.5' + typo3-version: '^12.4' + db-version: '8' + - php-version: '8.3' + typo3-version: '^12.4' db-version: '8' steps: - uses: actions/checkout@v3 @@ -151,10 +137,16 @@ jobs: - name: Setup MySQL uses: mirromutth/mysql-action@v1.1 with: - mysql version: '5.7' + mysql version: "${{ matrix.db-version }}" mysql database: 'typo3' mysql root password: 'root' + - name: Wait for MySQL + run: | + while ! mysqladmin ping --host=127.0.0.1 --password=root --silent; do + sleep 1 + done + - name: Install dependencies run: composer require --no-interaction --prefer-dist --no-progress "typo3/cms-backend:${{ matrix.typo3-version }}" "typo3/cms-core:${{ matrix.typo3-version }}" "typo3/cms-extbase:${{ matrix.typo3-version }}" "typo3/cms-frontend:${{ matrix.typo3-version }}" "typo3/cms-fluid-styled-content:${{ matrix.typo3-version }}" @@ -165,4 +157,16 @@ jobs: export typo3DatabaseHost="127.0.0.1" export typo3DatabaseUsername="root" export typo3DatabasePassword="root" - ./vendor/bin/phpunit --testdox + ./vendor/bin/phpunit + + tests-acceptance: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - uses: cachix/install-nix-action@v24 + with: + nix_path: nixpkgs=channel:nixos-unstable + + - name: Run Acceptance Tests + run: nix-shell --run project-test-acceptance diff --git a/.gitignore b/.gitignore index 51313d0..16c3c4b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ /.Build/ /composer.lock +/.phpunit.cache +/Tests/Acceptance/Support/_generated /vendor/ diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 0000000..5bd6dc4 --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,73 @@ +ignoreVCSIgnored(true) + ->in(realpath(__DIR__)) +; + +return (new \PhpCsFixer\Config()) + ->setRiskyAllowed(true) + ->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, + 'no_blank_lines_after_phpdoc' => true, + 'no_empty_phpdoc' => true, + 'no_empty_statement' => true, + '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, + 'ordered_imports' => true, + 'php_unit_construct' => ['assertions' => ['assertEquals', 'assertSame', 'assertNotEquals', 'assertNotSame']], + 'php_unit_mock_short_will_return' => true, + 'php_unit_test_case_static_method_calls' => ['call_type' => 'self'], + 'phpdoc_no_access' => true, + 'phpdoc_no_package' => true, + 'phpdoc_order' => ['order' => ['test', 'dataProvider', 'param', 'throws', 'return']], + 'phpdoc_scalar' => true, + 'phpdoc_separation' => ['groups' => [['Extbase\\*']]], + 'phpdoc_trim' => true, + 'phpdoc_types' => true, + 'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'], + 'return_type_declaration' => ['space_before' => 'none'], + '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, + 'yoda_style' => ['equal' => false, 'identical' => false, 'less_and_greater' => false], + ]) + ->setFinder($finder) +; diff --git a/Classes/Command/ImportConfigurationCommand.php b/Classes/Command/ImportConfigurationCommand.php index 95e4dad..c8b1630 100644 --- a/Classes/Command/ImportConfigurationCommand.php +++ b/Classes/Command/ImportConfigurationCommand.php @@ -34,24 +34,11 @@ use WerkraumMedia\ThueCat\Domain\Repository\Backend\ImportConfigurationRepositor class ImportConfigurationCommand extends Command { - /** - * @var ImportConfigurationRepository - */ - private $importConfigurationRepository; - - /** - * @var Importer - */ - private $importer; - public function __construct( - ImportConfigurationRepository $importConfigurationRepository, - Importer $importer + private readonly ImportConfigurationRepository $importConfigurationRepository, + private readonly Importer $importer ) { parent::__construct(); - - $this->importConfigurationRepository = $importConfigurationRepository; - $this->importer = $importer; } protected function configure(): void diff --git a/Classes/Controller/Backend/AbstractController.php b/Classes/Controller/Backend/AbstractController.php index 489e862..fe4ed3c 100644 --- a/Classes/Controller/Backend/AbstractController.php +++ b/Classes/Controller/Backend/AbstractController.php @@ -23,22 +23,30 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Controller\Backend; -use TYPO3\CMS\Backend\View\BackendTemplateView; +use Psr\Http\Message\ResponseInterface; +use TYPO3\CMS\Backend\Template\ModuleTemplate; +use TYPO3\CMS\Backend\Template\ModuleTemplateFactory; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; abstract class AbstractController extends ActionController { - /** - * BackendTemplateContainer - * - * @var BackendTemplateView - */ - protected $view; + private ModuleTemplateFactory $moduleTemplateFactory; - /** - * Backend Template Container - * - * @var string - */ - protected $defaultViewObjectName = BackendTemplateView::class; + protected ModuleTemplate $moduleTemplate; + + public function injectModuleTemplateFactory(ModuleTemplateFactory $moduleTemplateFactory): void + { + $this->moduleTemplateFactory = $moduleTemplateFactory; + } + + protected function initializeView(): void + { + $this->moduleTemplate = $this->moduleTemplateFactory->create($this->request); + $this->moduleTemplate->assign('settings', $this->settings); + } + + protected function htmlResponse(?string $html = null): ResponseInterface + { + return parent::htmlResponse($html ?? $this->moduleTemplate->render()); + } } diff --git a/Classes/Controller/Backend/ConfigurationController.php b/Classes/Controller/Backend/ConfigurationController.php index 91e1847..18dfc38 100644 --- a/Classes/Controller/Backend/ConfigurationController.php +++ b/Classes/Controller/Backend/ConfigurationController.php @@ -23,34 +23,25 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Controller\Backend; +use Psr\Http\Message\ResponseInterface; use WerkraumMedia\ThueCat\Domain\Repository\Backend\ImportConfigurationRepository; use WerkraumMedia\ThueCat\Domain\Repository\Backend\OrganisationRepository; class ConfigurationController extends AbstractController { - /** - * @var OrganisationRepository - */ - private $organisationRepository; - - /** - * @var ImportConfigurationRepository - */ - private $importConfigurationRepository; - public function __construct( - OrganisationRepository $organisationRepository, - ImportConfigurationRepository $importConfigurationRepository + private readonly OrganisationRepository $organisationRepository, + private readonly ImportConfigurationRepository $importConfigurationRepository ) { - $this->organisationRepository = $organisationRepository; - $this->importConfigurationRepository = $importConfigurationRepository; } - public function indexAction(): void + public function indexAction(): ResponseInterface { - $this->view->assignMultiple([ + $this->moduleTemplate->assignMultiple([ 'importConfigurations' => $this->importConfigurationRepository->findAll(), 'organisations' => $this->organisationRepository->findAll(), ]); + + return $this->htmlResponse(); } } diff --git a/Classes/Controller/Backend/ImportController.php b/Classes/Controller/Backend/ImportController.php index 09f20dc..396eefb 100644 --- a/Classes/Controller/Backend/ImportController.php +++ b/Classes/Controller/Backend/ImportController.php @@ -23,8 +23,9 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Controller\Backend; -use TYPO3\CMS\Core\Messaging\AbstractMessage; -use TYPO3\CMS\Extbase\Annotation as Extbase; +use Psr\Http\Message\ResponseInterface; +use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity; +use TYPO3\CMS\Extbase\Annotation\IgnoreValidation; use WerkraumMedia\ThueCat\Domain\Import\Importer; use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration; use WerkraumMedia\ThueCat\Domain\Repository\Backend\ImportLogRepository; @@ -33,42 +34,24 @@ use WerkraumMedia\ThueCat\Typo3Wrapper\TranslationService; class ImportController extends AbstractController { - /** - * @var Importer - */ - private $importer; - - /** - * @var ImportLogRepository - */ - private $repository; - - /** - * @var TranslationService - */ - private $translation; - public function __construct( - Importer $importer, - ImportLogRepository $repository, - TranslationService $translation + private readonly Importer $importer, + private readonly ImportLogRepository $repository, + private readonly TranslationService $translation ) { - $this->importer = $importer; - $this->repository = $repository; - $this->translation = $translation; } - public function indexAction(): void + public function indexAction(): ResponseInterface { - $this->view->assignMultiple([ + $this->moduleTemplate->assignMultiple([ 'imports' => $this->repository->findAll(), ]); + + return $this->htmlResponse(); } - /** - * @Extbase\IgnoreValidation("importConfiguration") - */ - public function importAction(ImportConfiguration $importConfiguration): void + #[IgnoreValidation(['argumentName' => 'importConfiguration'])] + public function importAction(ImportConfiguration $importConfiguration): ResponseInterface { $importLog = $this->importer->importConfiguration($importConfiguration); @@ -78,7 +61,7 @@ class ImportController extends AbstractController $this->createImportDoneFlashMessage($importConfiguration); } - $this->redirect('index', 'Backend\Configuration'); + return $this->redirect('index', 'Backend\Configuration'); } private function createImportErrorFlashMessage(ImportConfiguration $importConfiguration): void @@ -93,7 +76,7 @@ class ImportController extends AbstractController 'controller.backend.import.import.error.title', Extension::EXTENSION_NAME ), - AbstractMessage::ERROR + ContextualFeedbackSeverity::ERROR ); } @@ -109,7 +92,7 @@ class ImportController extends AbstractController 'controller.backend.import.import.success.title', Extension::EXTENSION_NAME ), - AbstractMessage::OK + ContextualFeedbackSeverity::OK ); } } diff --git a/Classes/DependencyInjection/ConverterPass.php b/Classes/DependencyInjection/ConverterPass.php index a07eaf4..d2356e8 100644 --- a/Classes/DependencyInjection/ConverterPass.php +++ b/Classes/DependencyInjection/ConverterPass.php @@ -29,7 +29,7 @@ use WerkraumMedia\ThueCat\Domain\Import\Typo3Converter\Registry; class ConverterPass implements CompilerPassInterface { - public const TAG = 'thuecat.typo3.converter'; + final public const TAG = 'thuecat.typo3.converter'; public function process(ContainerBuilder $container): void { diff --git a/Classes/DependencyInjection/EntityPass.php b/Classes/DependencyInjection/EntityPass.php index 8bff4b6..34288bd 100644 --- a/Classes/DependencyInjection/EntityPass.php +++ b/Classes/DependencyInjection/EntityPass.php @@ -29,7 +29,7 @@ use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\EntityRegistry; class EntityPass implements CompilerPassInterface { - public const TAG = 'thuecat.entity'; + final public const TAG = 'thuecat.entity'; public function process(ContainerBuilder $container): void { diff --git a/Classes/DependencyInjection/UrlProvidersPass.php b/Classes/DependencyInjection/UrlProvidersPass.php index 0edd3b2..ba6473c 100644 --- a/Classes/DependencyInjection/UrlProvidersPass.php +++ b/Classes/DependencyInjection/UrlProvidersPass.php @@ -29,7 +29,7 @@ use WerkraumMedia\ThueCat\Domain\Import\UrlProvider\Registry; class UrlProvidersPass implements CompilerPassInterface { - public const TAG = 'thuecat:urlprovider'; + final public const TAG = 'thuecat:urlprovider'; public function process(ContainerBuilder $container): void { diff --git a/Classes/Domain/Import/Entity/AccessibilityCertification.php b/Classes/Domain/Import/Entity/AccessibilityCertification.php index 16f790d..761e7dd 100644 --- a/Classes/Domain/Import/Entity/AccessibilityCertification.php +++ b/Classes/Domain/Import/Entity/AccessibilityCertification.php @@ -27,45 +27,21 @@ use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\PropertyValues; class AccessibilityCertification implements MapsToType { - /** - * @var string - */ - protected $accessibilityCertificationStatus = ''; + protected string $accessibilityCertificationStatus = ''; - /** - * @var string - */ - protected $certificationAccessibilityDeaf = ''; + protected string $certificationAccessibilityDeaf = ''; - /** - * @var string - */ - protected $certificationAccessibilityMental = ''; + protected string $certificationAccessibilityMental = ''; - /** - * @var string - */ - protected $certificationAccessibilityPartiallyDeaf = ''; + protected string $certificationAccessibilityPartiallyDeaf = ''; - /** - * @var string - */ - protected $certificationAccessibilityPartiallyVisual = ''; + protected string $certificationAccessibilityPartiallyVisual = ''; - /** - * @var string - */ - protected $certificationAccessibilityVisual = ''; + protected string $certificationAccessibilityVisual = ''; - /** - * @var string - */ - protected $certificationAccessibilityWalking = ''; + protected string $certificationAccessibilityWalking = ''; - /** - * @var string - */ - protected $certificationAccessibilityWheelchair = ''; + protected string $certificationAccessibilityWheelchair = ''; public function getAccessibilityCertificationStatus(): string { @@ -109,6 +85,7 @@ class AccessibilityCertification implements MapsToType /** * @internal for mapping via Symfony component. + * * @param string|array $accessibilityCertificationStatus */ public function setAccessibilityCertificationStatus($accessibilityCertificationStatus): void @@ -121,6 +98,7 @@ class AccessibilityCertification implements MapsToType /** * @internal for mapping via Symfony component. + * * @param string|array $certificationAccessibilityDeaf */ public function setCertificationAccessibilityDeaf($certificationAccessibilityDeaf): void @@ -133,6 +111,7 @@ class AccessibilityCertification implements MapsToType /** * @internal for mapping via Symfony component. + * * @param string|array $certificationAccessibilityMental */ public function setCertificationAccessibilityMental($certificationAccessibilityMental): void @@ -145,6 +124,7 @@ class AccessibilityCertification implements MapsToType /** * @internal for mapping via Symfony component. + * * @param string|array $certificationAccessibilityPartiallyDeaf */ public function setCertificationAccessibilityPartiallyDeaf($certificationAccessibilityPartiallyDeaf): void @@ -157,6 +137,7 @@ class AccessibilityCertification implements MapsToType /** * @internal for mapping via Symfony component. + * * @param string|array $certificationAccessibilityPartiallyVisual */ public function setCertificationAccessibilityPartiallyVisual($certificationAccessibilityPartiallyVisual): void @@ -169,6 +150,7 @@ class AccessibilityCertification implements MapsToType /** * @internal for mapping via Symfony component. + * * @param string|array $certificationAccessibilityVisual */ public function setCertificationAccessibilityVisual($certificationAccessibilityVisual): void @@ -181,6 +163,7 @@ class AccessibilityCertification implements MapsToType /** * @internal for mapping via Symfony component. + * * @param string|array $certificationAccessibilityWalking */ public function setCertificationAccessibilityWalking($certificationAccessibilityWalking): void @@ -193,6 +176,7 @@ class AccessibilityCertification implements MapsToType /** * @internal for mapping via Symfony component. + * * @param string|array $certificationAccessibilityWheelchair */ public function setCertificationAccessibilityWheelchair($certificationAccessibilityWheelchair): void diff --git a/Classes/Domain/Import/Entity/AccessibilitySpecification.php b/Classes/Domain/Import/Entity/AccessibilitySpecification.php index 8f788d9..68ca3bd 100644 --- a/Classes/Domain/Import/Entity/AccessibilitySpecification.php +++ b/Classes/Domain/Import/Entity/AccessibilitySpecification.php @@ -27,45 +27,21 @@ use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\PropertyValues; class AccessibilitySpecification implements MapsToType { - /** - * @var AccessibilityCertification - */ - protected $accessibilityCertification; + protected AccessibilityCertification $accessibilityCertification; - /** - * @var array - */ - protected $accessibilitySearchCriteria = []; + protected array $accessibilitySearchCriteria = []; - /** - * @var string - */ - protected $shortDescriptionAccessibilityAllGenerations = ''; + protected string $shortDescriptionAccessibilityAllGenerations = ''; - /** - * @var string - */ - protected $shortDescriptionAccessibilityAllergic = ''; + protected string $shortDescriptionAccessibilityAllergic = ''; - /** - * @var string - */ - protected $shortDescriptionAccessibilityDeaf = ''; + protected string $shortDescriptionAccessibilityDeaf = ''; - /** - * @var string - */ - protected $shortDescriptionAccessibilityMental = ''; + protected string $shortDescriptionAccessibilityMental = ''; - /** - * @var string - */ - protected $shortDescriptionAccessibilityVisual = ''; + protected string $shortDescriptionAccessibilityVisual = ''; - /** - * @var string - */ - protected $shortDescriptionAccessibilityWalking = ''; + protected string $shortDescriptionAccessibilityWalking = ''; public function getAccessibilityCertification(): ?AccessibilityCertification { diff --git a/Classes/Domain/Import/Entity/Base.php b/Classes/Domain/Import/Entity/Base.php index 6bd88a4..3efcba1 100644 --- a/Classes/Domain/Import/Entity/Base.php +++ b/Classes/Domain/Import/Entity/Base.php @@ -30,17 +30,14 @@ class Base extends Minimum { use ManagedBy; - /** - * @var ForeignReference - */ - protected $photo; + protected ?ForeignReference $photo = null; /** * Images of this Thing. * * @var ForeignReference[] */ - protected $images = []; + protected array $images = []; public function getPhoto(): ?ForeignReference { @@ -65,6 +62,7 @@ class Base extends Minimum /** * @internal for mapping via Symfony component. + * * @return ForeignReference[] */ public function getImage(): array diff --git a/Classes/Domain/Import/Entity/MapsToType.php b/Classes/Domain/Import/Entity/MapsToType.php index c65c57a..e3301fd 100644 --- a/Classes/Domain/Import/Entity/MapsToType.php +++ b/Classes/Domain/Import/Entity/MapsToType.php @@ -35,6 +35,7 @@ interface MapsToType * - thuecat:TouristInformation * - thuecat:Town * - … + * * @return string[] */ public static function getSupportedTypes(): array; diff --git a/Classes/Domain/Import/Entity/MediaObject.php b/Classes/Domain/Import/Entity/MediaObject.php index aaf6ebc..7026acf 100644 --- a/Classes/Domain/Import/Entity/MediaObject.php +++ b/Classes/Domain/Import/Entity/MediaObject.php @@ -27,30 +27,18 @@ use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\ForeignReference; class MediaObject extends Minimum implements MapsToType { - /** - * @var int - */ - protected $copyrightYear = 0; + protected int $copyrightYear = 0; - /** - * @var string - */ - protected $license = ''; + protected string $license = ''; - /** - * @var string - */ - protected $licenseAuthor = ''; + protected string $licenseAuthor = ''; /** * @var string|ForeignReference */ protected $author; - /** - * @var string - */ - protected $type = ''; + protected string $type = ''; public function getCopyrightYear(): int { @@ -85,7 +73,7 @@ class MediaObject extends Minimum implements MapsToType */ public function setCopyrightYear(string $copyrightYear): void { - $this->copyrightYear = (int) $copyrightYear; + $this->copyrightYear = (int)$copyrightYear; } /** @@ -106,6 +94,7 @@ class MediaObject extends Minimum implements MapsToType /** * @internal for mapping via Symfony component. + * * @param string|ForeignReference $author */ public function setAuthor($author): void diff --git a/Classes/Domain/Import/Entity/Minimum.php b/Classes/Domain/Import/Entity/Minimum.php index 32dc453..b8424d9 100644 --- a/Classes/Domain/Import/Entity/Minimum.php +++ b/Classes/Domain/Import/Entity/Minimum.php @@ -29,33 +29,27 @@ abstract class Minimum * URL to the original source at ThüCAT. * Not unique within our system. We have one entity per language, * while ThüCAT has a single entity containing all languages. - * - * @var string */ - protected $id = ''; + protected string $id = ''; /** * Short name of the thing. * Can be translated. - * - * @var string */ - protected $name = ''; + protected string $name = ''; /** * Long text describing the thing. * Can be translated. - * - * @var string */ - protected $description = ''; + protected string $description = ''; /** * URL to official version of this thing outside of ThüCAT. * * @var string[] */ - protected $urls = []; + protected array $urls = []; public function getId(): string { @@ -108,6 +102,7 @@ abstract class Minimum /** * @internal for mapping via Symfony component. + * * @param string|array $url */ public function setUrl($url): void diff --git a/Classes/Domain/Import/Entity/Person.php b/Classes/Domain/Import/Entity/Person.php index d30c2fb..4bb692e 100644 --- a/Classes/Domain/Import/Entity/Person.php +++ b/Classes/Domain/Import/Entity/Person.php @@ -25,15 +25,9 @@ namespace WerkraumMedia\ThueCat\Domain\Import\Entity; class Person extends Base implements MapsToType { - /** - * @var string - */ - protected $givenName = ''; + protected string $givenName = ''; - /** - * @var string - */ - protected $familyName = ''; + protected string $familyName = ''; public function getGivenName(): string { diff --git a/Classes/Domain/Import/Entity/Place.php b/Classes/Domain/Import/Entity/Place.php index 208e10a..4f67767 100644 --- a/Classes/Domain/Import/Entity/Place.php +++ b/Classes/Domain/Import/Entity/Place.php @@ -23,14 +23,15 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Import\Entity; +use DateTimeImmutable; use TYPO3\CMS\Core\Utility\GeneralUtility; -use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\PropertyValues; use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\Address; use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\ForeignReference; use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\Geo; use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\OpeningHour; use WerkraumMedia\ThueCat\Domain\Import\Entity\Shared\ContainedInPlace; use WerkraumMedia\ThueCat\Domain\Import\Entity\Shared\Organization; +use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\PropertyValues; use WerkraumMedia\ThueCat\Service\DateBasedFilter; class Place extends Base @@ -38,60 +39,48 @@ class Place extends Base use Organization; use ContainedInPlace; - /** - * @var Address - */ - protected $address; + protected ?Address $address = null; - /** - * @var Geo - */ - protected $geo; + protected ?Geo $geo = null; /** * @var OpeningHour[] */ - protected $openingHoursSpecifications = []; + protected array $openingHoursSpecifications = []; /** * @var OpeningHour[] */ - protected $specialOpeningHours = []; + protected array $specialOpeningHours = []; /** * @var ForeignReference[] */ - protected $parkingFacilitiesNearBy = []; + protected array $parkingFacilitiesNearBy = []; /** * @var string[] */ - protected $sanitations = []; + protected array $sanitations = []; /** * @var string[] */ - protected $otherServices = []; + protected array $otherServices = []; /** * @var string[] */ - protected $trafficInfrastructures = []; + protected array $trafficInfrastructures = []; /** * @var string[] */ - protected $paymentsAccepted = []; + protected array $paymentsAccepted = []; - /** - * @var string - */ - protected $distanceToPublicTransport = ''; + protected string $distanceToPublicTransport = ''; - /** - * @var ForeignReference - */ - protected $accessibilitySpecification; + protected ?ForeignReference $accessibilitySpecification = null; public function getAddress(): ?Address { @@ -161,10 +150,11 @@ class Place extends Base return GeneralUtility::makeInstance(DateBasedFilter::class) ->filterOutPreviousDates( $this->openingHoursSpecifications, - function (OpeningHour $hour): ?\DateTimeImmutable { + function (OpeningHour $hour): ?DateTimeImmutable { return $hour->getValidThrough(); } - ); + ) + ; } /** @@ -175,10 +165,11 @@ class Place extends Base return GeneralUtility::makeInstance(DateBasedFilter::class) ->filterOutPreviousDates( $this->specialOpeningHours, - function (OpeningHour $hour): ?\DateTimeImmutable { + function (OpeningHour $hour): ?DateTimeImmutable { return $hour->getValidThrough(); } - ); + ) + ; } /** @@ -252,6 +243,7 @@ class Place extends Base /** * @internal for mapping via Symfony component. + * * @param string|array $sanitation */ public function setSanitation($sanitation): void @@ -265,6 +257,7 @@ class Place extends Base /** * @internal for mapping via Symfony component. + * * @param string|array $otherService */ public function setOtherService($otherService): void @@ -278,6 +271,7 @@ class Place extends Base /** * @internal for mapping via Symfony component. + * * @param string|array $trafficInfrastructure */ public function setTrafficInfrastructure($trafficInfrastructure): void @@ -291,6 +285,7 @@ class Place extends Base /** * @internal for mapping via Symfony component. + * * @param string|array $paymentAccepted */ public function setPaymentAccepted($paymentAccepted): void diff --git a/Classes/Domain/Import/Entity/Properties/Address.php b/Classes/Domain/Import/Entity/Properties/Address.php index 0776e5d..587c4bc 100644 --- a/Classes/Domain/Import/Entity/Properties/Address.php +++ b/Classes/Domain/Import/Entity/Properties/Address.php @@ -25,35 +25,17 @@ namespace WerkraumMedia\ThueCat\Domain\Import\Entity\Properties; class Address { - /** - * @var string - */ - protected $streetAddress = ''; + protected string $streetAddress = ''; - /** - * @var string - */ - protected $addressLocality = ''; + protected string $addressLocality = ''; - /** - * @var string - */ - protected $postalCode = ''; + protected string $postalCode = ''; - /** - * @var string - */ - protected $telephone = ''; + protected string $telephone = ''; - /** - * @var string - */ - protected $faxNumber = ''; + protected string $faxNumber = ''; - /** - * @var string - */ - protected $email = ''; + protected string $email = ''; public function getStreetAddress(): string { diff --git a/Classes/Domain/Import/Entity/Properties/DayOfWeek.php b/Classes/Domain/Import/Entity/Properties/DayOfWeek.php index 0055df4..cd577dd 100644 --- a/Classes/Domain/Import/Entity/Properties/DayOfWeek.php +++ b/Classes/Domain/Import/Entity/Properties/DayOfWeek.php @@ -25,14 +25,8 @@ namespace WerkraumMedia\ThueCat\Domain\Import\Entity\Properties; class DayOfWeek { - /** - * @var string - */ - protected $dayOfWeek = ''; - public function __construct( - string $dayOfWeek + protected string $dayOfWeek ) { - $this->dayOfWeek = $dayOfWeek; } } diff --git a/Classes/Domain/Import/Entity/Properties/ForeignReference.php b/Classes/Domain/Import/Entity/Properties/ForeignReference.php index 5b48af3..e6fa2bc 100644 --- a/Classes/Domain/Import/Entity/Properties/ForeignReference.php +++ b/Classes/Domain/Import/Entity/Properties/ForeignReference.php @@ -33,10 +33,8 @@ class ForeignReference * URL to the original source at ThüCAT. * Not unique within our system. We have one entity per language, * while ThüCAT has a single entity containing all languages. - * - * @var string */ - protected $id = ''; + protected string $id = ''; public function getId(): string { diff --git a/Classes/Domain/Import/Entity/Properties/Geo.php b/Classes/Domain/Import/Entity/Properties/Geo.php index 275dcba..4cbc587 100644 --- a/Classes/Domain/Import/Entity/Properties/Geo.php +++ b/Classes/Domain/Import/Entity/Properties/Geo.php @@ -25,15 +25,9 @@ namespace WerkraumMedia\ThueCat\Domain\Import\Entity\Properties; class Geo { - /** - * @var float - */ - protected $longitude = 0.00; + protected float $longitude = 0.00; - /** - * @var float - */ - protected $latitude = 0.00; + protected float $latitude = 0.00; public function getLongitude(): float { @@ -50,7 +44,7 @@ class Geo */ public function setLongitude(string $longitude): void { - $this->longitude = (float) $longitude; + $this->longitude = (float)$longitude; } /** @@ -58,6 +52,6 @@ class Geo */ public function setLatitude(string $latitude): void { - $this->latitude = (float) $latitude; + $this->latitude = (float)$latitude; } } diff --git a/Classes/Domain/Import/Entity/Properties/Offer.php b/Classes/Domain/Import/Entity/Properties/Offer.php index 0592126..8367f23 100644 --- a/Classes/Domain/Import/Entity/Properties/Offer.php +++ b/Classes/Domain/Import/Entity/Properties/Offer.php @@ -23,20 +23,20 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Import\Entity\Properties; -use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\PropertyValues; use WerkraumMedia\ThueCat\Domain\Import\Entity\Minimum; +use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\PropertyValues; class Offer extends Minimum { /** * @var string[] */ - protected $offerTypes = []; + protected array $offerTypes = []; /** * @var PriceSpecification[] */ - protected $prices = []; + protected array $prices = []; /** * @return string[] @@ -48,6 +48,7 @@ class Offer extends Minimum /** * @internal for mapping via Symfony component. + * * @param string|array $offerType */ public function setOfferType($offerType): void @@ -57,7 +58,7 @@ class Offer extends Minimum } $this->offerTypes = array_map( - [PropertyValues::class, 'removePrefixFromEntry'], + PropertyValues::removePrefixFromEntry(...), $offerType ); } @@ -72,6 +73,7 @@ class Offer extends Minimum /** * @return PriceSpecification[] + * * @internal for mapping via Symfony component. */ public function getPriceSpecification(): array diff --git a/Classes/Domain/Import/Entity/Properties/OpeningHour.php b/Classes/Domain/Import/Entity/Properties/OpeningHour.php index 357da02..99b5d60 100644 --- a/Classes/Domain/Import/Entity/Properties/OpeningHour.php +++ b/Classes/Domain/Import/Entity/Properties/OpeningHour.php @@ -23,49 +23,39 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Import\Entity\Properties; +use DateTimeImmutable; + class OpeningHour { - /** - * @var \DateTimeImmutable|null - */ - protected $validFrom = null; + protected ?DateTimeImmutable $validFrom = null; - /** - * @var \DateTimeImmutable|null - */ - protected $validThrough = null; + protected ?DateTimeImmutable $validThrough = null; - /** - * @var \DateTimeImmutable - */ - protected $opens; + protected DateTimeImmutable $opens; - /** - * @var \DateTimeImmutable - */ - protected $closes; + protected DateTimeImmutable $closes; /** * @var string[] */ - protected $daysOfWeek = []; + protected array $daysOfWeek = []; - public function getValidFrom(): ?\DateTimeImmutable + public function getValidFrom(): ?DateTimeImmutable { return $this->validFrom; } - public function getValidThrough(): ?\DateTimeImmutable + public function getValidThrough(): ?DateTimeImmutable { return $this->validThrough; } - public function getOpens(): \DateTimeImmutable + public function getOpens(): DateTimeImmutable { return $this->opens; } - public function getCloses(): \DateTimeImmutable + public function getCloses(): DateTimeImmutable { return $this->closes; } @@ -81,7 +71,7 @@ class OpeningHour /** * @internal for mapping via Symfony component. */ - public function setValidFrom(\DateTimeImmutable $validFrom): void + public function setValidFrom(DateTimeImmutable $validFrom): void { $this->validFrom = $validFrom; } @@ -89,7 +79,7 @@ class OpeningHour /** * @internal for mapping via Symfony component. */ - public function setValidThrough(\DateTimeImmutable $validThrough): void + public function setValidThrough(DateTimeImmutable $validThrough): void { $this->validThrough = $validThrough; } @@ -97,7 +87,7 @@ class OpeningHour /** * @internal for mapping via Symfony component. */ - public function setOpens(\DateTimeImmutable $opens): void + public function setOpens(DateTimeImmutable $opens): void { $this->opens = $opens; } @@ -105,7 +95,7 @@ class OpeningHour /** * @internal for mapping via Symfony component. */ - public function setCloses(\DateTimeImmutable $closes): void + public function setCloses(DateTimeImmutable $closes): void { $this->closes = $closes; } diff --git a/Classes/Domain/Import/Entity/Properties/PriceSpecification.php b/Classes/Domain/Import/Entity/Properties/PriceSpecification.php index 6d93ee8..3d6617f 100644 --- a/Classes/Domain/Import/Entity/Properties/PriceSpecification.php +++ b/Classes/Domain/Import/Entity/Properties/PriceSpecification.php @@ -23,31 +23,24 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Import\Entity\Properties; -use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\PropertyValues; use WerkraumMedia\ThueCat\Domain\Import\Entity\Minimum; +use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\PropertyValues; class PriceSpecification extends Minimum { - /** - * @var float - */ - protected $price = 0.00; + protected float $price = 0.00; /** * E.g. 'EUR' * ThueCat specific format. - * - * @var string */ - protected $currency = ''; + protected string $currency = ''; /** * E.g. 'PerPerson' * ThueCat specific property. - * - * @var array */ - protected $calculationRules = []; + protected array $calculationRules = []; public function getPrice(): float { @@ -85,6 +78,7 @@ class PriceSpecification extends Minimum /** * @internal for mapping via Symfony component. + * * @param string|array $calculationRule */ public function setCalculationRule($calculationRule): void diff --git a/Classes/Domain/Import/Entity/Shared/ContainedInPlace.php b/Classes/Domain/Import/Entity/Shared/ContainedInPlace.php index 95929d1..a760589 100644 --- a/Classes/Domain/Import/Entity/Shared/ContainedInPlace.php +++ b/Classes/Domain/Import/Entity/Shared/ContainedInPlace.php @@ -42,6 +42,7 @@ trait ContainedInPlace /** * @return ForeignReference[] + * * @internal for mapping via Symfony component. */ public function getContainedInPlace(): array diff --git a/Classes/Domain/Import/Entity/Shared/ManagedBy.php b/Classes/Domain/Import/Entity/Shared/ManagedBy.php index e12de9a..50115f2 100644 --- a/Classes/Domain/Import/Entity/Shared/ManagedBy.php +++ b/Classes/Domain/Import/Entity/Shared/ManagedBy.php @@ -29,10 +29,8 @@ trait ManagedBy { /** * The Thing responsible for the data within this Thing. - * - * @var ForeignReference */ - protected $managedBy; + protected ?ForeignReference $managedBy = null; public function getManagedBy(): ?ForeignReference { diff --git a/Classes/Domain/Import/Entity/Shared/Organization.php b/Classes/Domain/Import/Entity/Shared/Organization.php index bfd1710..62e2047 100644 --- a/Classes/Domain/Import/Entity/Shared/Organization.php +++ b/Classes/Domain/Import/Entity/Shared/Organization.php @@ -34,7 +34,7 @@ trait Organization /** * @var Offer[] */ - protected $offers = []; + protected array $offers = []; /** * @return Offer[] @@ -46,6 +46,7 @@ trait Organization /** * @internal for mapping via Symfony component. + * * @return Offer[] */ public function getMakesOffer(): array diff --git a/Classes/Domain/Import/Entity/TouristAttraction.php b/Classes/Domain/Import/Entity/TouristAttraction.php index fd2579a..0e6648d 100644 --- a/Classes/Domain/Import/Entity/TouristAttraction.php +++ b/Classes/Domain/Import/Entity/TouristAttraction.php @@ -27,55 +27,40 @@ use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\PropertyValues; class TouristAttraction extends Place implements MapsToType { - /** - * @var string - */ - protected $slogan = ''; + protected string $slogan = ''; - /** - * @var string - */ - protected $startOfConstruction = ''; + protected string $startOfConstruction = ''; /** * @var string[] */ - protected $museumServices = []; + protected array $museumServices = []; /** * @var string[] */ - protected $architecturalStyles = []; + protected array $architecturalStyles = []; /** * @var string[] */ - protected $digitalOffers = []; + protected array $digitalOffers = []; /** * @var string[] */ - protected $photographies = []; + protected array $photographies = []; - /** - * @var string - */ - protected $petsAllowed = ''; + protected string $petsAllowed = ''; - /** - * @var string - */ - protected $isAccessibleForFree = ''; + protected string $isAccessibleForFree = ''; - /** - * @var string - */ - protected $publicAccess = ''; + protected string $publicAccess = ''; /** * @var string[] */ - protected $availableLanguages = []; + protected array $availableLanguages = []; public function getSlogan(): string { @@ -160,6 +145,7 @@ class TouristAttraction extends Place implements MapsToType /** * @internal for mapping via Symfony component. + * * @param string|array $museumService */ public function setMuseumService($museumService): void @@ -173,6 +159,7 @@ class TouristAttraction extends Place implements MapsToType /** * @internal for mapping via Symfony component. + * * @param string|array $architecturalStyle */ public function setArchitecturalStyle($architecturalStyle): void @@ -186,6 +173,7 @@ class TouristAttraction extends Place implements MapsToType /** * @internal for mapping via Symfony component. + * * @param string|array $digitalOffer */ public function setDigitalOffer($digitalOffer): void @@ -199,6 +187,7 @@ class TouristAttraction extends Place implements MapsToType /** * @internal for mapping via Symfony component. + * * @param string|array $photography */ public function setPhotography($photography): void @@ -236,6 +225,7 @@ class TouristAttraction extends Place implements MapsToType /** * @internal for mapping via Symfony component. + * * @param string|array $availableLanguage */ public function setAvailableLanguage($availableLanguage): void diff --git a/Classes/Domain/Import/EntityMapper.php b/Classes/Domain/Import/EntityMapper.php index d82fed2..5fe5a9f 100644 --- a/Classes/Domain/Import/EntityMapper.php +++ b/Classes/Domain/Import/EntityMapper.php @@ -30,6 +30,7 @@ use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Serializer; +use Throwable; use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\ArrayDenormalizer; use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\CustomAnnotationExtractor; use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\JsonDecode; @@ -50,12 +51,12 @@ class EntityMapper try { return $serializer->deserialize( - json_encode($jsonLD), + json_encode($jsonLD, JSON_THROW_ON_ERROR), $targetClassName, 'json', $context ); - } catch (\Throwable $e) { + } catch (Throwable $e) { throw new MappingException($jsonLD, $targetClassName, $e); } } diff --git a/Classes/Domain/Import/EntityMapper/CustomAnnotationExtractor.php b/Classes/Domain/Import/EntityMapper/CustomAnnotationExtractor.php index 282d0ec..936b6fa 100644 --- a/Classes/Domain/Import/EntityMapper/CustomAnnotationExtractor.php +++ b/Classes/Domain/Import/EntityMapper/CustomAnnotationExtractor.php @@ -23,13 +23,21 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Import\EntityMapper; +use function in_array; +use InvalidArgumentException; use LogicException; use phpDocumentor\Reflection\DocBlock; +use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag; +use phpDocumentor\Reflection\DocBlock\Tags\Param; use phpDocumentor\Reflection\DocBlockFactory; use phpDocumentor\Reflection\DocBlockFactoryInterface; -use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag; use phpDocumentor\Reflection\Types\Context; use phpDocumentor\Reflection\Types\ContextFactory; +use ReflectionClass; +use ReflectionException; +use ReflectionMethod; +use ReflectionProperty; +use RuntimeException; use Symfony\Component\PropertyInfo\Extractor\ConstructorArgumentTypeExtractorInterface; use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; use Symfony\Component\PropertyInfo\PropertyDescriptionExtractorInterface; @@ -46,26 +54,26 @@ use Symfony\Component\PropertyInfo\Util\PhpDocTypeHelper; */ class CustomAnnotationExtractor implements PropertyDescriptionExtractorInterface, PropertyTypeExtractorInterface, ConstructorArgumentTypeExtractorInterface { - public const PROPERTY = 0; - public const ACCESSOR = 1; - public const MUTATOR = 2; + final public const PROPERTY = 0; + final public const ACCESSOR = 1; + final public const MUTATOR = 2; /** * @var array */ - private $docBlocks = []; + private array $docBlocks = []; /** * @var Context[] */ - private $contexts = []; + private array $contexts = []; - private $docBlockFactory; - private $contextFactory; - private $phpDocTypeHelper; - private $mutatorPrefixes; - private $accessorPrefixes; - private $arrayMutatorPrefixes; + private readonly \phpDocumentor\Reflection\DocBlockFactoryInterface $docBlockFactory; + private readonly \phpDocumentor\Reflection\Types\ContextFactory $contextFactory; + private readonly \Symfony\Component\PropertyInfo\Util\PhpDocTypeHelper $phpDocTypeHelper; + private readonly array $mutatorPrefixes; + private readonly array $accessorPrefixes; + private readonly array $arrayMutatorPrefixes; /** * @param string[]|null $mutatorPrefixes @@ -75,7 +83,7 @@ class CustomAnnotationExtractor implements PropertyDescriptionExtractorInterface public function __construct(DocBlockFactoryInterface $docBlockFactory = null, array $mutatorPrefixes = null, array $accessorPrefixes = null, array $arrayMutatorPrefixes = null) { if (!class_exists(DocBlockFactory::class)) { - throw new \LogicException(sprintf('Unable to use the "%s" class as the "phpdocumentor/reflection-docblock" package is not installed. Try running composer require "phpdocumentor/reflection-docblock".', __CLASS__)); + throw new LogicException(sprintf('Unable to use the "%s" class as the "phpdocumentor/reflection-docblock" package is not installed. Try running composer require "phpdocumentor/reflection-docblock".', self::class)); } $this->docBlockFactory = $docBlockFactory ?: DocBlockFactory::createInstance(); @@ -129,7 +137,7 @@ class CustomAnnotationExtractor implements PropertyDescriptionExtractorInterface $contents = $docBlock->getDescription()->render(); - return '' === $contents ? null : $contents; + return $contents === '' ? null : $contents; } /** @@ -161,7 +169,7 @@ class CustomAnnotationExtractor implements PropertyDescriptionExtractorInterface $types = []; /** @var DocBlock\Tags\Var_|DocBlock\Tags\Return_|DocBlock\Tags\Param $tag */ foreach ($docBlock->getTagsByName($tag) as $tag) { - if ($tag && !$tag instanceof InvalidTag && null !== $tag->getType()) { + if ($tag && !$tag instanceof InvalidTag && $tag->getType() !== null) { foreach ($this->phpDocTypeHelper->getTypes($tag->getType()) as $type) { switch ($type->getClassName()) { case 'self': @@ -189,7 +197,7 @@ class CustomAnnotationExtractor implements PropertyDescriptionExtractorInterface return null; } - if (!\in_array($prefix, $this->arrayMutatorPrefixes)) { + if (!in_array($prefix, $this->arrayMutatorPrefixes)) { return $types; } @@ -210,12 +218,12 @@ class CustomAnnotationExtractor implements PropertyDescriptionExtractorInterface $types = []; /** @var DocBlock\Tags\Var_|DocBlock\Tags\Return_|DocBlock\Tags\Param $tag */ foreach ($docBlock->getTagsByName('param') as $tag) { - if ($tag && null !== $tag->getType()) { + if ($tag && $tag->getType() !== null) { $types[] = $this->phpDocTypeHelper->getTypes($tag->getType()); } } - if (!isset($types[0]) || [] === $types[0]) { + if (!isset($types[0]) || $types[0] === []) { return null; } @@ -225,8 +233,8 @@ class CustomAnnotationExtractor implements PropertyDescriptionExtractorInterface private function getDocBlockFromConstructor(string $class, string $property): ?DocBlock { try { - $reflectionClass = new \ReflectionClass($class); - } catch (\ReflectionException $e) { + $reflectionClass = new ReflectionClass($class); + } catch (ReflectionException $e) { return null; } $reflectionConstructor = $reflectionClass->getConstructor(); @@ -238,7 +246,7 @@ class CustomAnnotationExtractor implements PropertyDescriptionExtractorInterface $docBlock = $this->docBlockFactory->create($reflectionConstructor, $this->contextFactory->createFromReflector($reflectionConstructor)); return $this->filterDocBlockParams($docBlock, $property); - } catch (\InvalidArgumentException $e) { + } catch (InvalidArgumentException) { return null; } } @@ -246,11 +254,18 @@ class CustomAnnotationExtractor implements PropertyDescriptionExtractorInterface private function filterDocBlockParams(DocBlock $docBlock, string $allowedParam): DocBlock { $tags = array_values(array_filter($docBlock->getTagsByName('param'), function ($tag) use ($allowedParam) { - return $tag instanceof DocBlock\Tags\Param && $allowedParam === $tag->getVariableName(); + return $tag instanceof Param && $allowedParam === $tag->getVariableName(); })); - return new DocBlock($docBlock->getSummary(), $docBlock->getDescription(), $tags, $docBlock->getContext(), - $docBlock->getLocation(), $docBlock->isTemplateStart(), $docBlock->isTemplateEnd()); + return new DocBlock( + $docBlock->getSummary(), + $docBlock->getDescription(), + $tags, + $docBlock->getContext(), + $docBlock->getLocation(), + $docBlock->isTemplateStart(), + $docBlock->isTemplateEnd() + ); } /** @@ -290,8 +305,8 @@ class CustomAnnotationExtractor implements PropertyDescriptionExtractorInterface { // Use a ReflectionProperty instead of $class to get the parent class if applicable try { - $reflectionProperty = new \ReflectionProperty($class, $property); - } catch (\ReflectionException $e) { + $reflectionProperty = new ReflectionProperty($class, $property); + } catch (ReflectionException $e) { return null; } @@ -305,7 +320,7 @@ class CustomAnnotationExtractor implements PropertyDescriptionExtractorInterface try { return $this->docBlockFactory->create($reflectionProperty, $this->createFromReflector($reflector)); - } catch (\InvalidArgumentException|\RuntimeException $e) { + } catch (InvalidArgumentException|RuntimeException) { return null; } } @@ -315,25 +330,25 @@ class CustomAnnotationExtractor implements PropertyDescriptionExtractorInterface */ private function getDocBlockFromMethod(string $class, string $ucFirstProperty, int $type): ?array { - $prefixes = self::ACCESSOR === $type ? $this->accessorPrefixes : $this->mutatorPrefixes; + $prefixes = $type === self::ACCESSOR ? $this->accessorPrefixes : $this->mutatorPrefixes; $prefix = null; foreach ($prefixes as $prefix) { - $methodName = $prefix.$ucFirstProperty; + $methodName = $prefix . $ucFirstProperty; try { - $reflectionMethod = new \ReflectionMethod($class, $methodName); + $reflectionMethod = new ReflectionMethod($class, $methodName); if ($reflectionMethod->isStatic()) { continue; } if ( - (self::ACCESSOR === $type && 0 === $reflectionMethod->getNumberOfRequiredParameters()) || - (self::MUTATOR === $type && $reflectionMethod->getNumberOfParameters() >= 1) + ($type === self::ACCESSOR && $reflectionMethod->getNumberOfRequiredParameters() === 0) || + ($type === self::MUTATOR && $reflectionMethod->getNumberOfParameters() >= 1) ) { break; } - } catch (\ReflectionException $e) { + } catch (ReflectionException) { // Try the next prefix if the method doesn't exist } } @@ -352,7 +367,7 @@ class CustomAnnotationExtractor implements PropertyDescriptionExtractorInterface try { return [$this->docBlockFactory->create($reflectionMethod, $this->createFromReflector($reflector)), $prefix]; - } catch (\InvalidArgumentException|\RuntimeException $e) { + } catch (InvalidArgumentException|RuntimeException) { return null; } } @@ -360,9 +375,9 @@ class CustomAnnotationExtractor implements PropertyDescriptionExtractorInterface /** * Prevents a lot of redundant calls to ContextFactory::createForNamespace(). */ - private function createFromReflector(\ReflectionClass $reflector): Context + private function createFromReflector(ReflectionClass $reflector): Context { - $cacheKey = $reflector->getNamespaceName().':'.$reflector->getFileName(); + $cacheKey = $reflector->getNamespaceName() . ':' . $reflector->getFileName(); if (isset($this->contexts[$cacheKey])) { return $this->contexts[$cacheKey]; diff --git a/Classes/Domain/Import/EntityMapper/EntityRegistry.php b/Classes/Domain/Import/EntityMapper/EntityRegistry.php index ad94dfb..3c54566 100644 --- a/Classes/Domain/Import/EntityMapper/EntityRegistry.php +++ b/Classes/Domain/Import/EntityMapper/EntityRegistry.php @@ -23,9 +23,6 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Import\EntityMapper; -use TYPO3\CMS\Core\Utility\ArrayUtility; - - /** * Registry with supported entities and their types. */ @@ -34,7 +31,7 @@ class EntityRegistry /** * @var array[] */ - private $entities = []; + private array $entities = []; /** * @param string[] $supportedTypes @@ -70,10 +67,9 @@ class EntityRegistry return ''; } - $matches = ArrayUtility::sortArraysByKey( - $matches, - 'priority' - ); + usort($matches, static function (array $configA, array $configB): int { + return $configA['priority'] <=> $configB['priority']; + }); return end($matches)['entityClassName']; } diff --git a/Classes/Domain/Import/EntityMapper/JsonDecode.php b/Classes/Domain/Import/EntityMapper/JsonDecode.php index 29c53f9..4e0c518 100644 --- a/Classes/Domain/Import/EntityMapper/JsonDecode.php +++ b/Classes/Domain/Import/EntityMapper/JsonDecode.php @@ -23,9 +23,8 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Import\EntityMapper; +use InvalidArgumentException; use Symfony\Component\Serializer\Encoder\JsonDecode as SymfonyJsonDecode; -use TYPO3\CMS\Core\Utility\StringUtility; - /** * Used to add further necessary normalization on decoding incoming JSON structure. @@ -34,12 +33,12 @@ use TYPO3\CMS\Core\Utility\StringUtility; */ class JsonDecode extends SymfonyJsonDecode { - public const ACTIVE_LANGUAGE = 'active_language'; + final public const ACTIVE_LANGUAGE = 'active_language'; /** * @var array[] */ - private $rulesToKeepTypeInfo = [ + private array $rulesToKeepTypeInfo = [ [ 'type' => 'beginsWith', 'comparisonValue' => 'thuecat:facilityAccessibility', @@ -50,14 +49,13 @@ class JsonDecode extends SymfonyJsonDecode string $data, string $format, array $context = [] - ) { + ): mixed { $context[self::ASSOCIATIVE] = true; $result = parent::decode($data, $format, $context); - $activeLanguage = $context[self::ACTIVE_LANGUAGE] ?? ''; if ($activeLanguage === '') { - throw new \InvalidArgumentException('Provide active language: ' . self::ACTIVE_LANGUAGE); + throw new InvalidArgumentException('Provide active language: ' . self::ACTIVE_LANGUAGE); } return $this->process( @@ -94,11 +92,11 @@ class JsonDecode extends SymfonyJsonDecode * * This decode will resolve the list to a single value based on current language settings from context. * - * @param mixed $value + * * @return mixed */ private function decodeLanguageSpecificValue( - &$value, + mixed &$value, string $activeLanguage ) { if (is_array($value) === false) { @@ -155,11 +153,11 @@ class JsonDecode extends SymfonyJsonDecode * * This decode will resolve single values wrapped in array with extra info. * - * @param mixed $value + * * @return mixed */ private function decodeSingleValues( - &$value + mixed &$value ) { if (is_array($value) === false) { return $value; @@ -189,11 +187,11 @@ class JsonDecode extends SymfonyJsonDecode /** * Prepare data structure for PHP \DateTimeImmutable. * - * @param mixed $value + * * @return mixed */ private function decodeDateTime( - &$value + mixed &$value ) { $supportedTypes = [ 'schema:Time', @@ -213,22 +211,21 @@ class JsonDecode extends SymfonyJsonDecode } /** - * @param mixed $key * @return mixed */ - private function mapKey($key) + private function mapKey(mixed $key) { if (is_string($key) === false) { return $key; } - if (StringUtility::beginsWith($key, '@')) { + if (str_starts_with($key, '@')) { return mb_substr($key, 1); } - if (StringUtility::beginsWith($key, 'schema:')) { + if (str_starts_with($key, 'schema:')) { return mb_substr($key, 7); } - if (StringUtility::beginsWith($key, 'thuecat:')) { + if (str_starts_with($key, 'thuecat:')) { return mb_substr($key, 8); } @@ -238,7 +235,7 @@ class JsonDecode extends SymfonyJsonDecode private function doesRuleMatch(array $rule, string $type): bool { if ($rule['type'] === 'beginsWith') { - return StringUtility::beginsWith($type, $rule['comparisonValue']); + return str_starts_with($type, (string)$rule['comparisonValue']); } return false; diff --git a/Classes/Domain/Import/EntityMapper/MappingException.php b/Classes/Domain/Import/EntityMapper/MappingException.php index 035860a..eb520a4 100644 --- a/Classes/Domain/Import/EntityMapper/MappingException.php +++ b/Classes/Domain/Import/EntityMapper/MappingException.php @@ -23,30 +23,21 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Import\EntityMapper; -class MappingException extends \Exception +use Exception; +use Throwable; + +class MappingException extends Exception { - /** - * @var array - */ - protected $jsonLD = []; - - /** - * @var string - */ - protected $targetClassName = ''; - public function __construct( - array $jsonLD, - string $targetClassName, - \Throwable $previous + protected array $jsonLD, + protected string $targetClassName, + Throwable $previous ) { parent::__construct( 'Could not map incoming JSON-LD to target object: ' . $previous->getMessage(), 1628157659, $previous ); - $this->jsonLD = $jsonLD; - $this->targetClassName = $targetClassName; } public function getUrl(): string diff --git a/Classes/Domain/Import/EntityMapper/PropertyValues.php b/Classes/Domain/Import/EntityMapper/PropertyValues.php index fb4969c..48885ef 100644 --- a/Classes/Domain/Import/EntityMapper/PropertyValues.php +++ b/Classes/Domain/Import/EntityMapper/PropertyValues.php @@ -36,7 +36,7 @@ class PropertyValues public static function removePrefixFromEntries(array $entriesWithPrefix): array { return array_map( - [PropertyValues::class, 'removePrefixFromEntry'], + PropertyValues::removePrefixFromEntry(...), $entriesWithPrefix ); } diff --git a/Classes/Domain/Import/Import.php b/Classes/Domain/Import/Import.php index 1311897..5923ce1 100644 --- a/Classes/Domain/Import/Import.php +++ b/Classes/Domain/Import/Import.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Import; +use InvalidArgumentException; use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration as Typo3ImportConfiguration; use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLog; @@ -37,27 +38,21 @@ class Import /** * @var ImportLog[] */ - private $importLogStack = []; + private array $importLogStack = []; /** * @var ImportConfiguration[] */ - private $configurationStack = []; + private array $configurationStack = []; - /** - * @var ImportLog - */ - private $currentImportLog; + private ImportLog $currentImportLog; - /** - * @var ImportConfiguration - */ - private $currentConfiguration; + private ImportConfiguration $currentConfiguration; public function start(ImportConfiguration $configuration): void { if (!$configuration instanceof Typo3ImportConfiguration) { - throw new \InvalidArgumentException('Currently only can process ImportConfiguration of TYPO3.', 1629708772); + throw new InvalidArgumentException('Currently only can process ImportConfiguration of TYPO3.', 1629708772); } $this->currentConfiguration = $configuration; diff --git a/Classes/Domain/Import/Importer.php b/Classes/Domain/Import/Importer.php index e67f056..b8a650a 100644 --- a/Classes/Domain/Import/Importer.php +++ b/Classes/Domain/Import/Importer.php @@ -23,12 +23,13 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Import; -use TYPO3\CMS\Core\Log\LogManager; +use Exception; use TYPO3\CMS\Core\Log\Logger; +use TYPO3\CMS\Core\Log\LogManager; +use WerkraumMedia\ThueCat\Domain\Import\Entity\MapsToType; use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\EntityRegistry; use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\JsonDecode; use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\MappingException; -use WerkraumMedia\ThueCat\Domain\Import\Entity\MapsToType; use WerkraumMedia\ThueCat\Domain\Import\Importer\Converter; use WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData; use WerkraumMedia\ThueCat\Domain\Import\Importer\Languages; @@ -42,76 +43,22 @@ use WerkraumMedia\ThueCat\Domain\Repository\Backend\ImportLogRepository; class Importer { - /** - * @var UrlProviderRegistry - */ - private $urls; + private readonly Logger $logger; - /** - * @var Converter - */ - private $converter; - - /** - * @var EntityRegistry - */ - private $entityRegistry; - - /** - * @var EntityMapper - */ - private $entityMapper; - - /** - * @var Languages - */ - private $languages; - - /** - * @var FetchData - */ - private $fetchData; - - /** - * @var SaveData - */ - private $saveData; - - /** - * @var ImportLogRepository - */ - private $importLogRepository; - - /** - * @var Logger - */ - private $logger; - - /** - * @var Import - */ - private $import; + private readonly Import $import; public function __construct( - UrlProviderRegistry $urls, - Converter $converter, - EntityRegistry $entityRegistry, - EntityMapper $entityMapper, - Languages $languages, - ImportLogRepository $importLogRepository, - FetchData $fetchData, - SaveData $saveData, + private readonly UrlProviderRegistry $urls, + private readonly Converter $converter, + private readonly EntityRegistry $entityRegistry, + private readonly EntityMapper $entityMapper, + private readonly Languages $languages, + private readonly ImportLogRepository $importLogRepository, + private readonly FetchData $fetchData, + private readonly SaveData $saveData, LogManager $logManager ) { - $this->urls = $urls; - $this->converter = $converter; - $this->entityRegistry = $entityRegistry; - $this->entityMapper = $entityMapper; - $this->languages = $languages; - $this->importLogRepository = $importLogRepository; - $this->fetchData = $fetchData; - $this->saveData = $saveData; - $this->logger = $logManager->getLogger(__CLASS__); + $this->logger = $logManager->getLogger(self::class); $this->import = new Import(); } @@ -139,7 +86,7 @@ class Importer { $urlProvider = $this->urls->getProviderForConfiguration($this->import->getConfiguration()); if (!$urlProvider instanceof UrlProvider) { - throw new \Exception('No URL Provider available for given configuration.', 1629296635); + throw new Exception('No URL Provider available for given configuration.', 1629296635); } foreach ($urlProvider->getUrls() as $url) { @@ -196,7 +143,7 @@ class Importer } if (!$mappedEntity instanceof MapsToType) { - $this->logger->error('Mapping did not result in an MapsToType instance.', ['class' => get_class($mappedEntity)]); + $this->logger->error('Mapping did not result in an MapsToType instance.', ['class' => $mappedEntity::class]); continue; } @@ -218,7 +165,8 @@ class Importer 'url' => $url, 'language' => $language, 'targetEntity' => $targetEntity, - ]); + ] + ); continue; } $entities->add($convertedEntity); diff --git a/Classes/Domain/Import/Importer/FetchData.php b/Classes/Domain/Import/Importer/FetchData.php index 5d5b2a0..544d3f8 100644 --- a/Classes/Domain/Import/Importer/FetchData.php +++ b/Classes/Domain/Import/Importer/FetchData.php @@ -32,39 +32,15 @@ use WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData\InvalidResponseExcept class FetchData { - /** - * @var RequestFactoryInterface - */ - private $requestFactory; + private string $databaseUrlPrefix = 'https://cdb.thuecat.org'; - /** - * @var ClientInterface - */ - private $httpClient; - - /** - * @var CacheFrontendInterface - */ - private $cache; - - /** - * @var string - */ - private $databaseUrlPrefix = 'https://cdb.thuecat.org'; - - /** - * @var string - */ - private $urlPrefix = 'https://thuecat.org'; + private string $urlPrefix = 'https://thuecat.org'; public function __construct( - RequestFactoryInterface $requestFactory, - ClientInterface $httpClient, - CacheFrontendInterface $cache + private readonly RequestFactoryInterface $requestFactory, + private readonly ClientInterface $httpClient, + private readonly CacheFrontendInterface $cache ) { - $this->requestFactory = $requestFactory; - $this->httpClient = $httpClient; - $this->cache = $cache; } public function updatedNodes(string $scopeId): array @@ -94,7 +70,7 @@ class FetchData $this->handleInvalidResponse($response, $request); - $jsonLD = json_decode((string) $response->getBody(), true); + $jsonLD = json_decode((string)$response->getBody(), true, 512, JSON_THROW_ON_ERROR); if (is_array($jsonLD)) { $this->cache->set($cacheIdentifier, $jsonLD); return $jsonLD; diff --git a/Classes/Domain/Import/Importer/FetchData/InvalidResponseException.php b/Classes/Domain/Import/Importer/FetchData/InvalidResponseException.php index 4568a56..b51528c 100644 --- a/Classes/Domain/Import/Importer/FetchData/InvalidResponseException.php +++ b/Classes/Domain/Import/Importer/FetchData/InvalidResponseException.php @@ -23,6 +23,8 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData; -class InvalidResponseException extends \RuntimeException +use RuntimeException; + +class InvalidResponseException extends RuntimeException { } diff --git a/Classes/Domain/Import/Importer/SaveData.php b/Classes/Domain/Import/Importer/SaveData.php index ac12613..10a7a64 100644 --- a/Classes/Domain/Import/Importer/SaveData.php +++ b/Classes/Domain/Import/Importer/SaveData.php @@ -33,26 +33,14 @@ use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLogEntry\SavingEntity; class SaveData { /** - * @var DataHandler + * @var string[] */ - private $dataHandler; - - /** - * @var ConnectionPool - */ - private $connectionPool; - - /** - * @var mixed[] - */ - private $errorLog; + private array $errorLog; public function __construct( - DataHandler $dataHandler, - ConnectionPool $connectionPool + private readonly DataHandler $dataHandler, + private readonly ConnectionPool $connectionPool ) { - $this->dataHandler = $dataHandler; - $this->connectionPool = $connectionPool; } public function import(EntityCollection $entityCollection, ImportLog $log): void @@ -78,7 +66,7 @@ class SaveData $identifier = $this->getIdentifier($entity); if (is_numeric($identifier)) { - $entity->setExistingTypo3Uid((int) $identifier); + $entity->setExistingTypo3Uid((int)$identifier); } } } @@ -155,7 +143,7 @@ class SaveData $existingUid = $this->getExistingUid($entity); if ($existingUid > 0) { - return (string) $existingUid; + return (string)$existingUid; } $identifier = 'NEW_' . sha1($entity->getRemoteId() . $entity->getTypo3SystemLanguageUid()); @@ -176,7 +164,8 @@ class SaveData $tableColumns = $this->connectionPool ->getConnectionForTable($entity->getTypo3DatabaseTableName()) ->getSchemaManager() - ->listTableColumns($entity->getTypo3DatabaseTableName()); + ->listTableColumns($entity->getTypo3DatabaseTableName()) + ; $queryBuilder = $this->connectionPool->getQueryBuilderForTable($entity->getTypo3DatabaseTableName()); $queryBuilder->getRestrictions()->removeAll(); @@ -193,9 +182,9 @@ class SaveData )); } - $result = $queryBuilder->execute()->fetchColumn(); + $result = $queryBuilder->executeQuery()->fetchOne(); if (is_numeric($result)) { - return (int) $result; + return (int)$result; } return 0; @@ -216,9 +205,9 @@ class SaveData $queryBuilder->createNamedParameter(0) )); - $result = $queryBuilder->execute()->fetchColumn(); + $result = $queryBuilder->executeQuery()->fetchOne(); if (is_numeric($result)) { - return (int) $result; + return (int)$result; } return 0; diff --git a/Classes/Domain/Import/Model/EntityCollection.php b/Classes/Domain/Import/Model/EntityCollection.php index f383c72..efad880 100644 --- a/Classes/Domain/Import/Model/EntityCollection.php +++ b/Classes/Domain/Import/Model/EntityCollection.php @@ -28,7 +28,7 @@ class EntityCollection /** * @var Entity[] */ - private $entities = []; + private array $entities = []; public function add(Entity $entity): void { @@ -61,8 +61,7 @@ class EntityCollection { return array_filter($this->entities, function (Entity $entity) { return $entity->isTranslation() - && $entity->exists() === false - ; + && $entity->exists() === false; }); } diff --git a/Classes/Domain/Import/Model/GenericEntity.php b/Classes/Domain/Import/Model/GenericEntity.php index 3046045..534fa99 100644 --- a/Classes/Domain/Import/Model/GenericEntity.php +++ b/Classes/Domain/Import/Model/GenericEntity.php @@ -25,53 +25,20 @@ namespace WerkraumMedia\ThueCat\Domain\Import\Model; class GenericEntity implements Entity { - /** - * @var int - */ - private $typo3StoragePid; + private bool $created = false; + + private int $typo3Uid = 0; /** - * @var string + * @param mixed[] $data */ - private $typo3DatabaseTableName; - - /** - * @var int - */ - private $typo3SystemLanguageUid; - - /** - * @var bool - */ - private $created = false; - - /** - * @var int - */ - private $typo3Uid = 0; - - /** - * @var string - */ - private $remoteId; - - /** - * @var mixed[] - */ - private $data; - public function __construct( - int $typo3StoragePid, - string $typo3DatabaseTableName, - int $typo3SystemLanguageUid, - string $remoteId, - array $data + private readonly int $typo3StoragePid, + private readonly string $typo3DatabaseTableName, + private readonly int $typo3SystemLanguageUid, + private readonly string $remoteId, + private readonly array $data ) { - $this->typo3StoragePid = $typo3StoragePid; - $this->typo3DatabaseTableName = $typo3DatabaseTableName; - $this->typo3SystemLanguageUid = $typo3SystemLanguageUid; - $this->remoteId = $remoteId; - $this->data = $data; } public function getTypo3StoragePid(): int diff --git a/Classes/Domain/Import/RequestFactory.php b/Classes/Domain/Import/RequestFactory.php index 2e9302d..bfba08a 100644 --- a/Classes/Domain/Import/RequestFactory.php +++ b/Classes/Domain/Import/RequestFactory.php @@ -32,29 +32,11 @@ use TYPO3\CMS\Core\Configuration\ExtensionConfiguration; class RequestFactory implements RequestFactoryInterface { - /** - * @var ExtensionConfiguration - */ - private $extensionConfiguration; - - /** - * @var RequestFactoryInterface - */ - private $requestFactory; - - /** - * @var UriFactoryInterface - */ - private $uriFactory; - public function __construct( - ExtensionConfiguration $extensionConfiguration, - RequestFactoryInterface $requestFactory, - UriFactoryInterface $uriFactory + private readonly ExtensionConfiguration $extensionConfiguration, + private readonly RequestFactoryInterface $requestFactory, + private readonly UriFactoryInterface $uriFactory ) { - $this->extensionConfiguration = $extensionConfiguration; - $this->requestFactory = $requestFactory; - $this->uriFactory = $uriFactory; } /** @@ -63,7 +45,7 @@ class RequestFactory implements RequestFactoryInterface public function createRequest(string $method, $uri): RequestInterface { if (!$uri instanceof UriInterface) { - $uri = $this->uriFactory->createUri((string) $uri); + $uri = $this->uriFactory->createUri((string)$uri); } $query = []; @@ -74,7 +56,7 @@ class RequestFactory implements RequestFactoryInterface try { $query['api_key'] = $this->extensionConfiguration->get('thuecat', 'apiKey'); - } catch (ExtensionConfigurationExtensionNotConfiguredException $e) { + } catch (ExtensionConfigurationExtensionNotConfiguredException) { // Nothing todo, not configured, don't add. } diff --git a/Classes/Domain/Import/ResolveForeignReference.php b/Classes/Domain/Import/ResolveForeignReference.php index cbd7b91..8f1aeaa 100644 --- a/Classes/Domain/Import/ResolveForeignReference.php +++ b/Classes/Domain/Import/ResolveForeignReference.php @@ -23,9 +23,9 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Import; +use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\ForeignReference; use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\EntityRegistry; use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\JsonDecode; -use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\ForeignReference; use WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData; use WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData\InvalidResponseException; @@ -38,29 +38,11 @@ use WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData\InvalidResponseExcept */ class ResolveForeignReference { - /** - * @var FetchData - */ - private $fetchData; - - /** - * @var EntityRegistry - */ - private $entityRegistry; - - /** - * @var EntityMapper - */ - private $entityMapper; - public function __construct( - FetchData $fetchData, - EntityRegistry $entityRegistry, - EntityMapper $entityMapper + private readonly FetchData $fetchData, + private readonly EntityRegistry $entityRegistry, + private readonly EntityMapper $entityMapper ) { - $this->fetchData = $fetchData; - $this->entityRegistry = $entityRegistry; - $this->entityMapper = $entityMapper; } public function resolve( @@ -69,7 +51,7 @@ class ResolveForeignReference ): ?object { try { $jsonLD = $this->fetchData->jsonLDFromUrl($foreignReference->getId()); - } catch (InvalidResponseException $e) { + } catch (InvalidResponseException) { return null; } @@ -94,6 +76,7 @@ class ResolveForeignReference /** * @param ForeignReference[] $foreignReferences + * * @return string[] */ public static function convertToRemoteIds(array $foreignReferences): array diff --git a/Classes/Domain/Import/Typo3Converter.php b/Classes/Domain/Import/Typo3Converter.php index d5719f3..eb98011 100644 --- a/Classes/Domain/Import/Typo3Converter.php +++ b/Classes/Domain/Import/Typo3Converter.php @@ -23,6 +23,8 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Import; +use Exception; +use InvalidArgumentException; use WerkraumMedia\ThueCat\Domain\Import\Entity\MapsToType; use WerkraumMedia\ThueCat\Domain\Import\Importer\Converter; use WerkraumMedia\ThueCat\Domain\Import\Model\Entity; @@ -32,15 +34,9 @@ use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration as Typo3Impor class Typo3Converter implements Converter { - /** - * @var Registry - */ - private $registry; - public function __construct( - Registry $registry + private readonly Registry $registry ) { - $this->registry = $registry; } public function convert( @@ -49,13 +45,13 @@ class Typo3Converter implements Converter string $language ): ?Entity { if (!$configuration instanceof Typo3ImportConfiguration) { - throw new \InvalidArgumentException('Only supports TYPO3 import configuration.', 1629710386); + throw new InvalidArgumentException('Only supports TYPO3 import configuration.', 1629710386); } $concreteConverter = $this->registry->getConverterBasedOnType($mapped); if (!$concreteConverter instanceof Typo3ConcreteConverter) { - throw new \Exception( - 'No TYPO3 Converter registered for given Entity "' . get_class($mapped) . '".', + throw new Exception( + 'No TYPO3 Converter registered for given Entity "' . $mapped::class . '".', 1628244329 ); } diff --git a/Classes/Domain/Import/Typo3Converter/GeneralConverter.php b/Classes/Domain/Import/Typo3Converter/GeneralConverter.php index 40613cb..4454dc4 100644 --- a/Classes/Domain/Import/Typo3Converter/GeneralConverter.php +++ b/Classes/Domain/Import/Typo3Converter/GeneralConverter.php @@ -23,8 +23,9 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Import\Typo3Converter; -use TYPO3\CMS\Core\Log\LogManager; +use Exception; use TYPO3\CMS\Core\Log\Logger; +use TYPO3\CMS\Core\Log\LogManager; use TYPO3\CMS\Extbase\Persistence\QueryResultInterface; use WerkraumMedia\ThueCat\Domain\Import\Entity\AccessibilitySpecification; use WerkraumMedia\ThueCat\Domain\Import\Entity\Base; @@ -52,55 +53,14 @@ use WerkraumMedia\ThueCat\Domain\Repository\Backend\TownRepository; class GeneralConverter implements Converter { - /** - * @var ResolveForeignReference - */ - private $resolveForeignReference; + private readonly Logger $logger; - /** - * @var Importer - */ - private $importer; - - /** - * @var LanguageHandling - */ - private $languageHandling; - - /** - * @var OrganisationRepository - */ - private $organisationRepository; - - /** - * @var TownRepository - */ - private $townRepository; - - /** - * @var ParkingFacilityRepository - */ - private $parkingFacilityRepository; - - /** - * @var NameExtractor - */ - private $nameExtractor; - - /** - * @var Logger - */ - private $logger; - - /** - * @var ImportConfiguration - */ - private $importConfiguration; + private ImportConfiguration $importConfiguration; /** * @var string[] */ - private $classToTableMapping = [ + private array $classToTableMapping = [ TouristAttraction::class => 'tx_thuecat_tourist_attraction', ParkingFacility::class => 'tx_thuecat_parking_facility', Town::class => 'tx_thuecat_town', @@ -110,23 +70,16 @@ class GeneralConverter implements Converter ]; public function __construct( - ResolveForeignReference $resolveForeignReference, - Importer $importer, - LanguageHandling $languageHandling, - OrganisationRepository $organisationRepository, - TownRepository $townRepository, - ParkingFacilityRepository $parkingFacilityRepository, - NameExtractor $nameExtractor, + private readonly ResolveForeignReference $resolveForeignReference, + private readonly Importer $importer, + private readonly LanguageHandling $languageHandling, + private readonly OrganisationRepository $organisationRepository, + private readonly TownRepository $townRepository, + private readonly ParkingFacilityRepository $parkingFacilityRepository, + private readonly NameExtractor $nameExtractor, LogManager $logManager ) { - $this->resolveForeignReference = $resolveForeignReference; - $this->importer = $importer; - $this->languageHandling = $languageHandling; - $this->organisationRepository = $organisationRepository; - $this->townRepository = $townRepository; - $this->parkingFacilityRepository = $parkingFacilityRepository; - $this->nameExtractor = $nameExtractor; - $this->logger = $logManager->getLogger(__CLASS__); + $this->logger = $logManager->getLogger(self::class); } public function convert( @@ -142,7 +95,7 @@ class GeneralConverter implements Converter $converted = new GenericEntity( $importConfiguration->getStoragePid(), - $this->getTableNameByEntityClass(get_class($entity)), + $this->getTableNameByEntityClass($entity::class), $this->languageHandling->getLanguageUidForString( $importConfiguration->getStoragePid(), $language @@ -167,12 +120,12 @@ class GeneralConverter implements Converter ImportConfiguration $importConfiguration, string $language ): bool { - $tableName = $this->getTableNameByEntityClass(get_class($entity)); + $tableName = $this->getTableNameByEntityClass($entity::class); if (!$entity instanceof Minimum) { $this->logger->info('Skipped conversion of entity, got unexpected type', [ 'expectedType' => Minimum::class, - 'actualType' => get_class($entity), + 'actualType' => $entity::class, ]); return false; } @@ -214,7 +167,7 @@ class GeneralConverter implements Converter { $tableName = $this->classToTableMapping[$className] ?? ''; if ($tableName == '') { - throw new \Exception('No table name configured for class ' . $className, 1629376990); + throw new Exception('No table name configured for class ' . $className, 1629376990); } return $tableName; @@ -298,7 +251,7 @@ class GeneralConverter implements Converter ) ); $town = $this->townRepository->findOneByEntity($entity); - return $town ? (string) $town->getUid() : ''; + return $town ? (string)$town->getUid() : ''; } private function getParkingFacilitiesNearByUids(Base $entity): array @@ -360,6 +313,7 @@ class GeneralConverter implements Converter if ($result === false || $result === '[]') { return '{}'; } + return $result; } @@ -393,7 +347,7 @@ class GeneralConverter implements Converter } } - return json_encode($data) ?: ''; + return json_encode($data, JSON_THROW_ON_ERROR) ?: ''; } private function getSingleMedia( @@ -433,7 +387,7 @@ class GeneralConverter implements Converter ]); } - return json_encode($data) ?: ''; + return json_encode($data, JSON_THROW_ON_ERROR) ?: ''; } private function getAddress(Place $entity): string @@ -462,7 +416,7 @@ class GeneralConverter implements Converter ]; } - return json_encode($data) ?: ''; + return json_encode($data, JSON_THROW_ON_ERROR) ?: ''; } private function getOffers(Place $entity): string @@ -473,11 +427,11 @@ class GeneralConverter implements Converter 'types' => $offer->getOfferTypes(), 'title' => $offer->getName(), 'description' => $offer->getDescription(), - 'prices' => array_map([$this, 'getPrice'], $offer->getPrices()), + 'prices' => array_map($this->getPrice(...), $offer->getPrices()), ]; } - return json_encode($data) ?: ''; + return json_encode($data, JSON_THROW_ON_ERROR) ?: ''; } private function getPrice(PriceSpecification $priceSpecification): array diff --git a/Classes/Domain/Import/Typo3Converter/LanguageHandling.php b/Classes/Domain/Import/Typo3Converter/LanguageHandling.php index 9b024d6..d80afbb 100644 --- a/Classes/Domain/Import/Typo3Converter/LanguageHandling.php +++ b/Classes/Domain/Import/Typo3Converter/LanguageHandling.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Import\Typo3Converter; +use InvalidArgumentException; use TYPO3\CMS\Core\Site\Entity\SiteLanguage; use TYPO3\CMS\Core\Site\SiteFinder; use WerkraumMedia\ThueCat\Domain\Import\ImportConfiguration; @@ -30,36 +31,30 @@ use WerkraumMedia\ThueCat\Domain\Import\Importer\Languages; class LanguageHandling implements Languages { - /** - * @var SiteFinder - */ - private $siteFinder; - public function __construct( - SiteFinder $siteFinder + private readonly SiteFinder $siteFinder ) { - $this->siteFinder = $siteFinder; } public function getAvailable(ImportConfiguration $configuration): array { if (method_exists($configuration, 'getStoragePid') === false) { - throw new \InvalidArgumentException('Unsupported configuration, need to retrieve storage pid.', 1629710300); + throw new InvalidArgumentException('Unsupported configuration, need to retrieve storage pid.', 1629710300); } return array_map(function (SiteLanguage $language) { - return $language->getTwoLetterIsoCode(); + return $language->getLocale()->getLanguageCode(); }, $this->getLanguages($configuration->getStoragePid())); } public function getLanguageUidForString(int $pageUid, string $isoCode): int { foreach ($this->getLanguages($pageUid) as $language) { - if ($language->getTwoLetterIsoCode() === $isoCode) { + if ($language->getLocale()->getLanguageCode() === $isoCode) { return $language->getLanguageId(); } } - throw new \InvalidArgumentException( + throw new InvalidArgumentException( sprintf( 'Could not find language for combination of page "%d" and iso code "%s".', $pageUid, diff --git a/Classes/Domain/Import/Typo3Converter/NameExtractor.php b/Classes/Domain/Import/Typo3Converter/NameExtractor.php index f87ae6d..85fdc24 100644 --- a/Classes/Domain/Import/Typo3Converter/NameExtractor.php +++ b/Classes/Domain/Import/Typo3Converter/NameExtractor.php @@ -28,15 +28,9 @@ use WerkraumMedia\ThueCat\Domain\Import\ResolveForeignReference; class NameExtractor { - /** - * @var ResolveForeignReference - */ - private $resolveForeignReference; - public function __construct( - ResolveForeignReference $resolveForeignReference + private readonly ResolveForeignReference $resolveForeignReference ) { - $this->resolveForeignReference = $resolveForeignReference; } /** @@ -65,7 +59,7 @@ class NameExtractor } if ($name === '' && method_exists($remote, 'getName')) { - $name = trim($remote->getName()); + $name = trim((string)$remote->getName()); } return $name; diff --git a/Classes/Domain/Import/Typo3Converter/Registry.php b/Classes/Domain/Import/Typo3Converter/Registry.php index 2b038e2..33b147c 100644 --- a/Classes/Domain/Import/Typo3Converter/Registry.php +++ b/Classes/Domain/Import/Typo3Converter/Registry.php @@ -37,7 +37,7 @@ class Registry /** * @var Converter[] */ - private $converters = []; + private array $converters = []; public function registerConverter(Converter $converter): void { diff --git a/Classes/Domain/Import/UrlProvider/ContainsPlaceUrlProvider.php b/Classes/Domain/Import/UrlProvider/ContainsPlaceUrlProvider.php index 8f0c752..af4016f 100644 --- a/Classes/Domain/Import/UrlProvider/ContainsPlaceUrlProvider.php +++ b/Classes/Domain/Import/UrlProvider/ContainsPlaceUrlProvider.php @@ -23,25 +23,17 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Import\UrlProvider; +use InvalidArgumentException; use WerkraumMedia\ThueCat\Domain\Import\ImportConfiguration; use WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData; class ContainsPlaceUrlProvider implements UrlProvider { - /** - * @var FetchData - */ - private $fetchData; - - /** - * @var string - */ - private $containsPlaceId = ''; + private string $containsPlaceId = ''; public function __construct( - FetchData $fetchData + private readonly FetchData $fetchData ) { - $this->fetchData = $fetchData; } public function canProvideForConfiguration( @@ -54,7 +46,7 @@ class ContainsPlaceUrlProvider implements UrlProvider ImportConfiguration $configuration ): UrlProvider { if (method_exists($configuration, 'getContainsPlaceId') === false) { - throw new \InvalidArgumentException('Received incompatible import configuration.', 1629709276); + throw new InvalidArgumentException('Received incompatible import configuration.', 1629709276); } $instance = clone $this; $instance->containsPlaceId = $configuration->getContainsPlaceId(); diff --git a/Classes/Domain/Import/UrlProvider/Registry.php b/Classes/Domain/Import/UrlProvider/Registry.php index 6595f5f..3fb0740 100644 --- a/Classes/Domain/Import/UrlProvider/Registry.php +++ b/Classes/Domain/Import/UrlProvider/Registry.php @@ -33,7 +33,7 @@ class Registry /** * @var UrlProvider[] */ - private $provider = []; + private array $provider = []; public function registerProvider(UrlProvider $provider): void { diff --git a/Classes/Domain/Import/UrlProvider/StaticUrlProvider.php b/Classes/Domain/Import/UrlProvider/StaticUrlProvider.php index 5b3b836..e907c7b 100644 --- a/Classes/Domain/Import/UrlProvider/StaticUrlProvider.php +++ b/Classes/Domain/Import/UrlProvider/StaticUrlProvider.php @@ -30,7 +30,7 @@ class StaticUrlProvider implements UrlProvider /** * @var string[] */ - private $urls = []; + private array $urls = []; public function canProvideForConfiguration( ImportConfiguration $configuration diff --git a/Classes/Domain/Import/UrlProvider/SyncScopeUrlProvider.php b/Classes/Domain/Import/UrlProvider/SyncScopeUrlProvider.php index 6afa5e4..7b4d827 100644 --- a/Classes/Domain/Import/UrlProvider/SyncScopeUrlProvider.php +++ b/Classes/Domain/Import/UrlProvider/SyncScopeUrlProvider.php @@ -23,25 +23,17 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Import\UrlProvider; +use InvalidArgumentException; use WerkraumMedia\ThueCat\Domain\Import\ImportConfiguration; use WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData; class SyncScopeUrlProvider implements UrlProvider { - /** - * @var FetchData - */ - private $fetchData; - - /** - * @var string - */ - private $syncScopeId = ''; + private string $syncScopeId = ''; public function __construct( - FetchData $fetchData + private readonly FetchData $fetchData ) { - $this->fetchData = $fetchData; } public function canProvideForConfiguration( @@ -54,7 +46,7 @@ class SyncScopeUrlProvider implements UrlProvider ImportConfiguration $configuration ): UrlProvider { if (method_exists($configuration, 'getSyncScopeId') === false) { - throw new \InvalidArgumentException('Received incompatible import configuration.', 1629709276); + throw new InvalidArgumentException('Received incompatible import configuration.', 1629709276); } $instance = clone $this; $instance->syncScopeId = $configuration->getSyncScopeId(); diff --git a/Classes/Domain/Model/Backend/AbstractEntity.php b/Classes/Domain/Model/Backend/AbstractEntity.php index c5c677b..c4e7e8e 100644 --- a/Classes/Domain/Model/Backend/AbstractEntity.php +++ b/Classes/Domain/Model/Backend/AbstractEntity.php @@ -23,29 +23,18 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Model\Backend; +use DateTimeImmutable; use TYPO3\CMS\Extbase\DomainObject\AbstractEntity as Typo3AbstractEntity; class AbstractEntity extends Typo3AbstractEntity { - /** - * @var string - */ - protected $remoteId = ''; + protected string $remoteId = ''; - /** - * @var string - */ - protected $title = ''; + protected string $title = ''; - /** - * @var string - */ - protected $description = ''; + protected string $description = ''; - /** - * @var \DateTimeImmutable|null - */ - protected $tstamp = null; + protected ?DateTimeImmutable $tstamp = null; public function getRemoteId(): string { @@ -62,7 +51,7 @@ class AbstractEntity extends Typo3AbstractEntity return $this->description; } - public function getLastImported(): ?\DateTimeImmutable + public function getLastImported(): ?DateTimeImmutable { return $this->tstamp; } diff --git a/Classes/Domain/Model/Backend/ImportConfiguration.php b/Classes/Domain/Model/Backend/ImportConfiguration.php index 86113b9..895a472 100644 --- a/Classes/Domain/Model/Backend/ImportConfiguration.php +++ b/Classes/Domain/Model/Backend/ImportConfiguration.php @@ -23,6 +23,8 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Model\Backend; +use DateTimeImmutable; +use Exception; use TYPO3\CMS\Core\Utility\ArrayUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\DomainObject\AbstractEntity; @@ -33,40 +35,28 @@ use WerkraumMedia\ThueCat\Domain\Import\ResolveForeignReference; class ImportConfiguration extends AbstractEntity implements ImportConfigurationInterface { - /** - * @var string - */ - protected $title = ''; + protected string $title = ''; - /** - * @var string - */ - protected $type = ''; + protected string $type = ''; - /** - * @var string - */ - protected $configuration = ''; + protected string $configuration = ''; - /** - * @var \DateTimeImmutable|null - */ - protected $tstamp = null; + protected ?DateTimeImmutable $tstamp = null; /** * @var ObjectStorage */ - protected $logs; + protected ObjectStorage $logs; /** * @var string[]|null */ - protected $urls = null; + protected ?array $urls = null; /** * @var string[] */ - protected $allowedTypes = []; + protected array $allowedTypes = []; public function __construct() { @@ -88,15 +78,15 @@ class ImportConfiguration extends AbstractEntity implements ImportConfigurationI return 'tx_thuecat_import_configuration'; } - public function getLastChanged(): ?\DateTimeImmutable + public function getLastChanged(): ?DateTimeImmutable { return $this->tstamp; } - public function getLastImported(): ?\DateTimeImmutable + public function getLastImported(): ?DateTimeImmutable { $lastImport = null; - $positionOfLastLog = (string) (count($this->logs) - 1); + $positionOfLastLog = count($this->logs) - 1; if ($this->logs->offsetExists($positionOfLastLog)) { $lastImport = $this->logs->offsetGet($positionOfLastLog); } @@ -112,7 +102,7 @@ class ImportConfiguration extends AbstractEntity implements ImportConfigurationI $storagePid = $this->getConfigurationValueFromFlexForm('storagePid'); if (is_numeric($storagePid) && $storagePid > 0) { - return intval($storagePid); + return (int)$storagePid; } return 0; @@ -151,7 +141,7 @@ class ImportConfiguration extends AbstractEntity implements ImportConfigurationI { $containsPlaceId = $this->getConfigurationValueFromFlexForm('containsPlaceId'); if (!is_string($containsPlaceId)) { - throw new \Exception('Could not fetch containsPlaceId.', 1671027015); + throw new Exception('Could not fetch containsPlaceId.', 1671027015); } return $containsPlaceId; } diff --git a/Classes/Domain/Model/Backend/ImportLog.php b/Classes/Domain/Model/Backend/ImportLog.php index ca094b8..b4e14be 100644 --- a/Classes/Domain/Model/Backend/ImportLog.php +++ b/Classes/Domain/Model/Backend/ImportLog.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Model\Backend; +use DateTimeImmutable; use TYPO3\CMS\Extbase\DomainObject\AbstractEntity as Typo3AbstractEntity; use TYPO3\CMS\Extbase\Persistence\ObjectStorage; use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLogEntry\SavingEntity; @@ -32,23 +33,14 @@ class ImportLog extends Typo3AbstractEntity /** * @var ObjectStorage */ - protected $logEntries; + protected ObjectStorage $logEntries; - /** - * @var ImportConfiguration|null - */ - protected $configuration = null; - - /** - * @var \DateTimeImmutable|null - */ - protected $crdate; + protected ?DateTimeImmutable $crdate = null; public function __construct( - ?ImportConfiguration $configuration = null + protected ?ImportConfiguration $configuration = null ) { $this->logEntries = new ObjectStorage(); - $this->configuration = $configuration; } public function addEntry(ImportLogEntry $entry): void @@ -78,7 +70,7 @@ class ImportLog extends Typo3AbstractEntity return $this->logEntries; } - public function getCreated(): ?\DateTimeImmutable + public function getCreated(): ?DateTimeImmutable { return $this->crdate; } diff --git a/Classes/Domain/Model/Backend/ImportLogEntry/MappingError.php b/Classes/Domain/Model/Backend/ImportLogEntry/MappingError.php index 12db1d3..ef13af6 100644 --- a/Classes/Domain/Model/Backend/ImportLogEntry/MappingError.php +++ b/Classes/Domain/Model/Backend/ImportLogEntry/MappingError.php @@ -23,26 +23,26 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLogEntry; +use Exception; use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\MappingException; use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLogEntry; class MappingError extends ImportLogEntry { - /** - * @var string - */ - protected $remoteId = ''; + protected string $remoteId = ''; /** + * Necessary for Extbase/Symfony. + * * @var string */ - protected $errors = ''; + protected string $errors = '[]'; public function __construct( MappingException $exception ) { $this->remoteId = $exception->getUrl(); - $this->errors = json_encode([$exception->getMessage()]) ?: ''; + $this->errors = json_encode([$exception->getMessage()], JSON_THROW_ON_ERROR) ?: ''; } public function getRemoteId(): string @@ -54,7 +54,7 @@ class MappingError extends ImportLogEntry { $errors = json_decode($this->errors, true); if (is_array($errors) === false) { - throw new \Exception('Could not parse errors.', 1671097690); + throw new Exception('Could not parse errors.', 1671097690); } return $errors; } diff --git a/Classes/Domain/Model/Backend/ImportLogEntry/SavingEntity.php b/Classes/Domain/Model/Backend/ImportLogEntry/SavingEntity.php index 4b61597..2ef6ecb 100644 --- a/Classes/Domain/Model/Backend/ImportLogEntry/SavingEntity.php +++ b/Classes/Domain/Model/Backend/ImportLogEntry/SavingEntity.php @@ -23,56 +23,42 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLogEntry; +use Exception; use WerkraumMedia\ThueCat\Domain\Import\Model\Entity; use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLogEntry; class SavingEntity extends ImportLogEntry { - /** - * @var string - */ - protected $remoteId = ''; + protected string $remoteId = ''; - /** - * @var bool - */ - protected $insertion = false; + protected bool $insertion = false; - /** - * @var int - */ - protected $recordUid = 0; + protected int $recordUid = 0; - /** - * @var int - */ - protected $recordPid = 0; + protected int $recordPid = 0; - /** - * @var string - */ - protected $tableName = ''; + protected string $tableName = ''; - /** - * @var string - */ - protected $errors = ''; + protected string $errors = ''; /** * @var string[] */ - protected $errorsAsArray = []; + protected array $errorsAsArray = []; + /** + * @param string[] $errorsAsArray + */ public function __construct( Entity $entity, - array $dataHandlerErrorLog + array $errorsAsArray ) { $this->remoteId = $entity->getRemoteId(); $this->insertion = $entity->wasCreated(); $this->recordUid = $entity->getTypo3Uid(); $this->recordPid = $entity->getTypo3StoragePid(); $this->tableName = $entity->getTypo3DatabaseTableName(); - $this->errorsAsArray = $dataHandlerErrorLog; + $this->errorsAsArray = $errorsAsArray; } public function getRemoteId(): string @@ -98,9 +84,9 @@ class SavingEntity extends ImportLogEntry public function getErrors(): array { if ($this->errorsAsArray === [] && $this->errors !== '') { - $errorsAsArray = json_decode($this->errors, true); + $errorsAsArray = json_decode($this->errors, true, 512, JSON_THROW_ON_ERROR); if (is_array($errorsAsArray) === false) { - throw new \Exception('Could not parse errors.', 1671097690); + throw new Exception('Could not parse errors.', 1671097690); } $this->errorsAsArray = array_unique($errorsAsArray); } @@ -121,7 +107,7 @@ class SavingEntity extends ImportLogEntry public function getInsertion(): array { return [ - 'insertion' => (int) $this->wasInsertion(), + 'insertion' => (int)$this->wasInsertion(), 'record_uid' => $this->getRecordUid(), 'table_name' => $this->getRecordDatabaseTableName(), ]; diff --git a/Classes/Domain/Model/Backend/Organisation.php b/Classes/Domain/Model/Backend/Organisation.php index 0064d10..05d359c 100644 --- a/Classes/Domain/Model/Backend/Organisation.php +++ b/Classes/Domain/Model/Backend/Organisation.php @@ -30,12 +30,12 @@ class Organisation extends AbstractEntity /** * @var ObjectStorage */ - protected $managesTowns; + protected ObjectStorage $managesTowns; /** * @var ObjectStorage */ - protected $managesTouristInformation; + protected ObjectStorage $managesTouristInformation; public function getManagesTowns(): ObjectStorage { diff --git a/Classes/Domain/Model/Backend/Town.php b/Classes/Domain/Model/Backend/Town.php index f41723c..4799b8d 100644 --- a/Classes/Domain/Model/Backend/Town.php +++ b/Classes/Domain/Model/Backend/Town.php @@ -30,7 +30,7 @@ class Town extends AbstractEntity /** * @var ObjectStorage */ - protected $touristInformation; + protected ObjectStorage $touristInformation; public function getTouristInformation(): ObjectStorage { diff --git a/Classes/Domain/Model/Frontend/AccessiblitySpecification.php b/Classes/Domain/Model/Frontend/AccessiblitySpecification.php index 8c78802..e83728e 100644 --- a/Classes/Domain/Model/Frontend/AccessiblitySpecification.php +++ b/Classes/Domain/Model/Frontend/AccessiblitySpecification.php @@ -27,19 +27,14 @@ use TYPO3\CMS\Core\Type\TypeInterface; class AccessiblitySpecification implements TypeInterface { - /** - * @var string - */ - private $serialized; - /** * @var mixed[] */ - private $data; + private array $data; - public function __construct(string $serialized) - { - $this->serialized = $serialized; + public function __construct( + private readonly string $serialized + ) { $this->data = json_decode($serialized, true); } diff --git a/Classes/Domain/Model/Frontend/Address.php b/Classes/Domain/Model/Frontend/Address.php index b29dbb4..5e08c15 100644 --- a/Classes/Domain/Model/Frontend/Address.php +++ b/Classes/Domain/Model/Frontend/Address.php @@ -27,20 +27,15 @@ use TYPO3\CMS\Core\Type\TypeInterface; class Address implements TypeInterface { - /** - * @var string - */ - private $serialized; - /** * @var mixed[] */ - private $data; + private array $data; - public function __construct(string $serialized) - { - $this->serialized = $serialized; - $this->data = json_decode($serialized, true); + public function __construct( + private readonly string $serialized + ) { + $this->data = json_decode($serialized, true) ?? []; } public function getStreet(): string diff --git a/Classes/Domain/Model/Frontend/Base.php b/Classes/Domain/Model/Frontend/Base.php index 985c415..02bfc2f 100644 --- a/Classes/Domain/Model/Frontend/Base.php +++ b/Classes/Domain/Model/Frontend/Base.php @@ -27,20 +27,11 @@ use TYPO3\CMS\Extbase\DomainObject\AbstractEntity; abstract class Base extends AbstractEntity { - /** - * @var string - */ - protected $title = ''; + protected string $title = ''; - /** - * @var string - */ - protected $description = ''; + protected string $description = ''; - /** - * @var Media|null - */ - protected $media = null; + protected ?Media $media = null; public function getTitle(): string { diff --git a/Classes/Domain/Model/Frontend/Media.php b/Classes/Domain/Model/Frontend/Media.php index 028e6c2..8c82522 100644 --- a/Classes/Domain/Model/Frontend/Media.php +++ b/Classes/Domain/Model/Frontend/Media.php @@ -28,24 +28,19 @@ use TYPO3\CMS\Core\Type\TypeInterface; class Media implements TypeInterface { - /** - * @var string - */ - private $serialized; - /** * @var array[] */ - private $data; + private readonly array $data; /** * @var FileReference[] */ - protected $editorialImages = []; + protected array $editorialImages = []; - public function __construct(string $serialized) - { - $this->serialized = $serialized; + public function __construct( + private readonly string $serialized + ) { $data = json_decode($serialized, true); $this->data = $this->prepareData(is_array($data) ? $data : []); } @@ -94,6 +89,7 @@ class Media implements TypeInterface /** * @internal Only used to set the values while mapping objects. + * * @see: AfterObjectThawedHandler */ public function setEditorialImages(array $images): void diff --git a/Classes/Domain/Model/Frontend/MergedOpeningHour.php b/Classes/Domain/Model/Frontend/MergedOpeningHour.php index 6ab9171..6958511 100644 --- a/Classes/Domain/Model/Frontend/MergedOpeningHour.php +++ b/Classes/Domain/Model/Frontend/MergedOpeningHour.php @@ -23,27 +23,23 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Model\Frontend; +use DateTimeImmutable; + class MergedOpeningHour { /** * @var MergedOpeningHourWeekDay[] */ - private $weekDays = []; + private array $weekDays = []; - /** - * @var \DateTimeImmutable|null - */ - private $from; + private readonly ?DateTimeImmutable $from; - /** - * @var \DateTimeImmutable|null - */ - private $through; + private readonly ?DateTimeImmutable $through; public function __construct( array $weekDays, - ?\DateTimeImmutable $from, - ?\DateTimeImmutable $through + ?DateTimeImmutable $from, + ?DateTimeImmutable $through ) { $this->weekDays = array_values($weekDays); $this->from = $from; @@ -72,12 +68,12 @@ class MergedOpeningHour ]); } - public function getFrom(): ?\DateTimeImmutable + public function getFrom(): ?DateTimeImmutable { return $this->from; } - public function getThrough(): ?\DateTimeImmutable + public function getThrough(): ?DateTimeImmutable { return $this->through; } diff --git a/Classes/Domain/Model/Frontend/MergedOpeningHourWeekDay.php b/Classes/Domain/Model/Frontend/MergedOpeningHourWeekDay.php index ad92c6c..814aa9c 100644 --- a/Classes/Domain/Model/Frontend/MergedOpeningHourWeekDay.php +++ b/Classes/Domain/Model/Frontend/MergedOpeningHourWeekDay.php @@ -27,29 +27,11 @@ use WerkraumMedia\ThueCat\Domain\TimingFormat; class MergedOpeningHourWeekDay { - /** - * @var string - */ - private $opens; - - /** - * @var string - */ - private $closes; - - /** - * @var string - */ - private $dayOfWeek; - public function __construct( - string $opens, - string $closes, - string $dayOfWeek + private readonly string $opens, + private readonly string $closes, + private readonly string $dayOfWeek ) { - $this->opens = $opens; - $this->closes = $closes; - $this->dayOfWeek = $dayOfWeek; } public function getOpens(): string diff --git a/Classes/Domain/Model/Frontend/MergedOpeningHours.php b/Classes/Domain/Model/Frontend/MergedOpeningHours.php index b93fff4..26cb3a1 100644 --- a/Classes/Domain/Model/Frontend/MergedOpeningHours.php +++ b/Classes/Domain/Model/Frontend/MergedOpeningHours.php @@ -23,17 +23,17 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Model\Frontend; -class MergedOpeningHours implements \Iterator, \Countable +use Countable; +use Iterator; + +class MergedOpeningHours implements Iterator, Countable { /** * @var MergedOpeningHour[] */ - private $openingHours = []; + private array $openingHours = []; - /** - * @var int - */ - private $position = 0; + private int $position = 0; /** * @param MergedOpeningHour[] $openingHours diff --git a/Classes/Domain/Model/Frontend/Offer.php b/Classes/Domain/Model/Frontend/Offer.php index 73a42b1..5052c48 100644 --- a/Classes/Domain/Model/Frontend/Offer.php +++ b/Classes/Domain/Model/Frontend/Offer.php @@ -27,45 +27,19 @@ use TYPO3\CMS\Core\Utility\ArrayUtility; class Offer { - /** - * @var string - */ - private $title; - - /** - * @var string[] - */ - private $types; - - /** - * @var string - */ - private $description; - - /** - * @var mixed[] - */ - private $prices; - /** * @param string[] $types + * @param mixed[] $prices */ private function __construct( - string $title, - array $types, - string $description, - array $prices + private readonly string $title, + private array $types, + private readonly string $description, + private readonly array $prices ) { - $this->title = $title; - $this->types = $types; - $this->description = $description; - $this->prices = $prices; } - /** - * @return Offer - */ - public static function createFromArray(array $rawData) + public static function createFromArray(array $rawData): Offer { $prices = []; @@ -95,7 +69,7 @@ class Offer public function getType(): string { $offerTypes = array_filter($this->types, function (string $type) { - return strpos($type, 'Offer') !== false; + return str_contains($type, 'Offer'); }); // Ensure clean index $offerTypes = array_values($offerTypes); diff --git a/Classes/Domain/Model/Frontend/Offers.php b/Classes/Domain/Model/Frontend/Offers.php index 9821edf..17a3765 100644 --- a/Classes/Domain/Model/Frontend/Offers.php +++ b/Classes/Domain/Model/Frontend/Offers.php @@ -23,31 +23,25 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Model\Frontend; +use Countable; +use Iterator; use TYPO3\CMS\Core\Type\TypeInterface; /** - * @implements \Iterator + * @implements Iterator */ -class Offers implements TypeInterface, \Iterator, \Countable +class Offers implements TypeInterface, Iterator, Countable { - /** - * @var string - */ - private $serialized = ''; - /** * @var mixed[] */ - private $array = []; + private array $array = []; - /** - * @var int - */ - private $position = 0; + private int $position = 0; - public function __construct(string $serialized) - { - $this->serialized = $serialized; + public function __construct( + private readonly string $serialized + ) { $array = json_decode($serialized, true); if (is_array($array)) { $array = array_map([Offer::class, 'createFromArray'], $array); diff --git a/Classes/Domain/Model/Frontend/OpeningHour.php b/Classes/Domain/Model/Frontend/OpeningHour.php index 5b03f32..3951979 100644 --- a/Classes/Domain/Model/Frontend/OpeningHour.php +++ b/Classes/Domain/Model/Frontend/OpeningHour.php @@ -23,63 +23,35 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Model\Frontend; +use DateTimeImmutable; +use DateTimeZone; use WerkraumMedia\ThueCat\Domain\TimingFormat; class OpeningHour { /** - * @var string + * @param mixed[] $daysOfWeek */ - private $opens; - - /** - * @var string - */ - private $closes; - - /** - * @var mixed[] - */ - private $daysOfWeek; - - /** - * @var \DateTimeImmutable|null - */ - private $from; - - /** - * @var \DateTimeImmutable|null - */ - private $through; - private function __construct( - string $opens, - string $closes, - array $daysOfWeek, - ?\DateTimeImmutable $from, - ?\DateTimeImmutable $through + private readonly string $opens, + private readonly string $closes, + private array $daysOfWeek, + private readonly ?DateTimeImmutable $from, + private readonly ?DateTimeImmutable $through ) { - $this->opens = $opens; - $this->closes = $closes; - $this->daysOfWeek = $daysOfWeek; - $this->from = $from; - $this->through = $through; } - /** - * @return OpeningHour - */ - public static function createFromArray(array $rawData) + public static function createFromArray(array $rawData): OpeningHour { $from = null; if (isset($rawData['from'])) { - $timeZone = new \DateTimeZone($rawData['from']['timezone'] ?? 'Europe/Berlin'); - $from = new \DateTimeImmutable($rawData['from']['date'], $timeZone); + $timeZone = new DateTimeZone($rawData['from']['timezone'] ?? 'Europe/Berlin'); + $from = new DateTimeImmutable($rawData['from']['date'], $timeZone); } $through = null; if (isset($rawData['through'])) { - $timeZone = new \DateTimeZone($rawData['through']['timezone'] ?? 'Europe/Berlin'); - $through = new \DateTimeImmutable($rawData['through']['date'], $timeZone); + $timeZone = new DateTimeZone($rawData['through']['timezone'] ?? 'Europe/Berlin'); + $through = new DateTimeImmutable($rawData['through']['date'], $timeZone); } return new self( @@ -120,12 +92,12 @@ class OpeningHour ]); } - public function getFrom(): ?\DateTimeImmutable + public function getFrom(): ?DateTimeImmutable { return $this->from; } - public function getThrough(): ?\DateTimeImmutable + public function getThrough(): ?DateTimeImmutable { return $this->through; } @@ -135,10 +107,9 @@ class OpeningHour $from = $this->getFrom(); $through = $this->getThrough(); - return $from instanceof \DateTimeImmutable - && $through instanceof \DateTimeImmutable - && $from->format('Ymd') === $through->format('Ymd') - ; + return $from instanceof DateTimeImmutable + && $through instanceof DateTimeImmutable + && $from->format('Ymd') === $through->format('Ymd'); } private function sortedDaysOfWeek(array $sorting): array diff --git a/Classes/Domain/Model/Frontend/OpeningHours.php b/Classes/Domain/Model/Frontend/OpeningHours.php index ed51800..6b07adb 100644 --- a/Classes/Domain/Model/Frontend/OpeningHours.php +++ b/Classes/Domain/Model/Frontend/OpeningHours.php @@ -23,33 +23,28 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Model\Frontend; +use Countable; +use DateTimeImmutable; +use Iterator; use TYPO3\CMS\Core\Type\TypeInterface; use TYPO3\CMS\Core\Utility\GeneralUtility; use WerkraumMedia\ThueCat\Service\DateBasedFilter; /** - * @implements \Iterator + * @implements Iterator */ -class OpeningHours implements TypeInterface, \Iterator, \Countable +class OpeningHours implements TypeInterface, Iterator, Countable { - /** - * @var string - */ - private $serialized = ''; - /** * @var mixed[] */ - private $array = []; + private array $array = []; - /** - * @var int - */ - private $position = 0; + private int $position = 0; - public function __construct(string $serialized) - { - $this->serialized = $serialized; + public function __construct( + private readonly string $serialized + ) { $this->array = $this->createArray($serialized); } @@ -63,10 +58,11 @@ class OpeningHours implements TypeInterface, \Iterator, \Countable $array = GeneralUtility::makeInstance(DateBasedFilter::class) ->filterOutPreviousDates( $array, - function (OpeningHour $hour): ?\DateTimeImmutable { + function (OpeningHour $hour): ?DateTimeImmutable { return $hour->getThrough(); } - ); + ) + ; usort($array, function (OpeningHour $hourA, OpeningHour $hourB) { return $hourA->getFrom() <=> $hourB->getFrom(); diff --git a/Classes/Domain/Model/Frontend/Place.php b/Classes/Domain/Model/Frontend/Place.php index 46a0f22..3b79474 100644 --- a/Classes/Domain/Model/Frontend/Place.php +++ b/Classes/Domain/Model/Frontend/Place.php @@ -28,60 +28,45 @@ use TYPO3\CMS\Extbase\Persistence\ObjectStorage; abstract class Place extends Base { - /** - * @var Address|null - */ - protected $address = null; + protected ?Address $address = null; - /** - * @var string - */ - protected $url = ''; + protected string $url = ''; - /** - * @var OpeningHours|null - */ - protected $openingHours = null; + protected ?OpeningHours $openingHours = null; - /** - * @var OpeningHours|null - */ - protected $specialOpeningHours = null; + protected ?OpeningHours $specialOpeningHours = null; /** * @var ObjectStorage */ - protected $parkingFacilityNearBy; + protected ObjectStorage $parkingFacilityNearBy; /** + * Necessary for Extbase/Symfony. + * * @var string */ - protected $sanitation = ''; + protected string $sanitation = ''; + + protected string $otherService = ''; + + protected string $trafficInfrastructure = ''; /** + * Necessary for Extbase/Symfony. + * * @var string */ - protected $otherService = ''; + protected string $paymentAccepted = ''; /** + * Necessary for Extbase/Symfony. + * * @var string */ - protected $trafficInfrastructure = ''; + protected string $distanceToPublicTransport = ''; - /** - * @var string - */ - protected $paymentAccepted = ''; - - /** - * @var string - */ - protected $distanceToPublicTransport = ''; - - /** - * @var AccessiblitySpecification|null - */ - protected $accessibilitySpecification = null; + protected ?AccessiblitySpecification $accessibilitySpecification = null; public function initializeObject(): void { diff --git a/Classes/Domain/Model/Frontend/Price.php b/Classes/Domain/Model/Frontend/Price.php index 795972a..95238ce 100644 --- a/Classes/Domain/Model/Frontend/Price.php +++ b/Classes/Domain/Model/Frontend/Price.php @@ -27,43 +27,13 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; class Price { - /** - * @var string - */ - private $title; - - /** - * @var string - */ - private $description; - - /** - * @var float - */ - private $price; - - /** - * @var string - */ - private $currency; - - /** - * @var string[] - */ - private $rules; - private function __construct( - string $title, - string $description, - float $price, - string $currency, - array $rules + private readonly string $title, + private readonly string $description, + private readonly float $price, + private readonly string $currency, + private readonly array $rules ) { - $this->title = $title; - $this->description = $description; - $this->price = $price; - $this->currency = $currency; - $this->rules = $rules; } /** diff --git a/Classes/Domain/Model/Frontend/TouristAttraction.php b/Classes/Domain/Model/Frontend/TouristAttraction.php index 1f3f169..7a85f42 100644 --- a/Classes/Domain/Model/Frontend/TouristAttraction.php +++ b/Classes/Domain/Model/Frontend/TouristAttraction.php @@ -27,60 +27,37 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; class TouristAttraction extends Place { + protected string $slogan = ''; + + protected ?Offers $offers = null; + + protected ?Town $town = null; + + protected string $startOfConstruction = ''; + + protected string $museumService = ''; + + protected string $architecturalStyle = ''; + /** + * Necessary for Extbase/Symfony. + * * @var string */ - protected $slogan = ''; - - /** - * @var Offers|null - */ - protected $offers = null; - - /** - * @var Town|null - */ - protected $town = null; + protected string $digitalOffer = ''; /** + * Necessary for Extbase/Symfony. + * * @var string */ - protected $startOfConstruction = ''; + protected string $photography = ''; - /** - * @var string - */ - protected $museumService = ''; + protected string $petsAllowed = ''; - /** - * @var string - */ - protected $architecturalStyle = ''; + protected string $isAccessibleForFree = ''; - /** - * @var string - */ - protected $digitalOffer = ''; - - /** - * @var string - */ - protected $photography = ''; - - /** - * @var string - */ - protected $petsAllowed = ''; - - /** - * @var string - */ - protected $isAccessibleForFree = ''; - - /** - * @var string - */ - protected $publicAccess = ''; + protected string $publicAccess = ''; public function getSlogan(): string { diff --git a/Classes/Domain/Repository/Backend/ImportConfigurationRepository.php b/Classes/Domain/Repository/Backend/ImportConfigurationRepository.php index f19354b..34a2b4f 100644 --- a/Classes/Domain/Repository/Backend/ImportConfigurationRepository.php +++ b/Classes/Domain/Repository/Backend/ImportConfigurationRepository.php @@ -23,7 +23,6 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Repository\Backend; -use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; use TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings; use TYPO3\CMS\Extbase\Persistence\Repository; use WerkraumMedia\ThueCat\Domain\Import\ImportConfiguration; @@ -31,10 +30,9 @@ use WerkraumMedia\ThueCat\Domain\Import\ImportConfiguration; class ImportConfigurationRepository extends Repository { public function __construct( - ObjectManagerInterface $objectManager, Typo3QuerySettings $querySettings ) { - parent::__construct($objectManager); + parent::__construct(); $querySettings->setRespectStoragePage(false); diff --git a/Classes/Domain/Repository/Backend/ImportLogRepository.php b/Classes/Domain/Repository/Backend/ImportLogRepository.php index a4fa8e9..8412277 100644 --- a/Classes/Domain/Repository/Backend/ImportLogRepository.php +++ b/Classes/Domain/Repository/Backend/ImportLogRepository.php @@ -24,7 +24,6 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Repository\Backend; use TYPO3\CMS\Core\DataHandling\DataHandler; -use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; use TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings; use TYPO3\CMS\Extbase\Persistence\QueryInterface; use TYPO3\CMS\Extbase\Persistence\Repository; @@ -32,19 +31,11 @@ use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLog; class ImportLogRepository extends Repository { - /** - * @var DataHandler - */ - private $dataHandler; - public function __construct( - ObjectManagerInterface $objectManager, - DataHandler $dataHandler, + private readonly DataHandler $dataHandler, Typo3QuerySettings $querySettings ) { - parent::__construct($objectManager); - - $this->dataHandler = $dataHandler; + parent::__construct(); $querySettings->setRespectStoragePage(false); $this->setDefaultQuerySettings($querySettings); @@ -84,7 +75,7 @@ class ImportLogRepository extends Repository 'import_log' => 'NEW0', 'type' => $entry->getType(), 'remote_id' => $entry->getRemoteId(), - 'errors' => json_encode($entry->getErrors()), + 'errors' => json_encode($entry->getErrors(), JSON_THROW_ON_ERROR), ] ); } diff --git a/Classes/Domain/Repository/Backend/OrganisationRepository.php b/Classes/Domain/Repository/Backend/OrganisationRepository.php index 29c21d3..446cb6c 100644 --- a/Classes/Domain/Repository/Backend/OrganisationRepository.php +++ b/Classes/Domain/Repository/Backend/OrganisationRepository.php @@ -23,7 +23,6 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Repository\Backend; -use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; use TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings; use TYPO3\CMS\Extbase\Persistence\Repository; use WerkraumMedia\ThueCat\Domain\Model\Backend\Organisation; @@ -34,10 +33,9 @@ use WerkraumMedia\ThueCat\Domain\Model\Backend\Organisation; class OrganisationRepository extends Repository { public function __construct( - ObjectManagerInterface $objectManager, Typo3QuerySettings $querySettings ) { - parent::__construct($objectManager); + parent::__construct(); $querySettings->setRespectStoragePage(false); $this->setDefaultQuerySettings($querySettings); diff --git a/Classes/Domain/Repository/Backend/ParkingFacilityRepository.php b/Classes/Domain/Repository/Backend/ParkingFacilityRepository.php index 45e9d23..1037b50 100644 --- a/Classes/Domain/Repository/Backend/ParkingFacilityRepository.php +++ b/Classes/Domain/Repository/Backend/ParkingFacilityRepository.php @@ -23,7 +23,6 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Repository\Backend; -use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; use TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings; use TYPO3\CMS\Extbase\Persistence\QueryResultInterface; use TYPO3\CMS\Extbase\Persistence\Repository; @@ -32,10 +31,9 @@ use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\ForeignReference; class ParkingFacilityRepository extends Repository { public function __construct( - ObjectManagerInterface $objectManager, Typo3QuerySettings $querySettings ) { - parent::__construct($objectManager); + parent::__construct(); $querySettings->setRespectStoragePage(false); diff --git a/Classes/Domain/Repository/Backend/TownRepository.php b/Classes/Domain/Repository/Backend/TownRepository.php index 7c47517..52e0d1f 100644 --- a/Classes/Domain/Repository/Backend/TownRepository.php +++ b/Classes/Domain/Repository/Backend/TownRepository.php @@ -23,7 +23,6 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Domain\Repository\Backend; -use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; use TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings; use TYPO3\CMS\Extbase\Persistence\Repository; use WerkraumMedia\ThueCat\Domain\Import\ResolveForeignReference; @@ -32,10 +31,9 @@ use WerkraumMedia\ThueCat\Domain\Model\Backend\Town; class TownRepository extends Repository { public function __construct( - ObjectManagerInterface $objectManager, Typo3QuerySettings $querySettings ) { - parent::__construct($objectManager); + parent::__construct(); $querySettings->setRespectStoragePage(false); diff --git a/Classes/Extension.php b/Classes/Extension.php index 382011d..7e1edd8 100644 --- a/Classes/Extension.php +++ b/Classes/Extension.php @@ -24,80 +24,30 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat; use TYPO3\CMS\Core\Cache\Backend\TransientMemoryBackend; -use TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider; -use TYPO3\CMS\Core\Imaging\IconRegistry; +use TYPO3\CMS\Core\DataHandling\PageDoktypeRegistry; use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; -use TYPO3\CMS\Extbase\Utility\ExtensionUtility; -use WerkraumMedia\ThueCat\Controller\Backend\ConfigurationController; -use WerkraumMedia\ThueCat\Controller\Backend\ImportController; class Extension { - public const EXTENSION_KEY = 'thuecat'; + final public const EXTENSION_KEY = 'thuecat'; - public const EXTENSION_NAME = 'Thuecat'; + final public const EXTENSION_NAME = 'Thuecat'; - public const TCA_SELECT_GROUP_IDENTIFIER = 'thuecat'; + final public const TCA_SELECT_GROUP_IDENTIFIER = 'thuecat'; - public const PAGE_DOKTYPE_TOURIST_ATTRACTION = 950; + final public const PAGE_DOKTYPE_TOURIST_ATTRACTION = 950; public static function getLanguagePath(): string { return 'LLL:EXT:' . self::EXTENSION_KEY . '/Resources/Private/Language/'; } - public static function registerBackendModules(): void - { - ExtensionUtility::registerModule( - self::EXTENSION_NAME, - 'thuecat', - '', - '', - [], - [ - 'access' => 'user,group', - 'icon' => self::getIconPath() . 'ModuleGroup.svg', - 'labels' => self::getLanguagePath() . 'locallang_mod.xlf', - ] - ); - ExtensionUtility::registerModule( - self::EXTENSION_NAME, - 'thuecat', - 'configurations', - '', - [ - ConfigurationController::class => 'index', - ImportController::class => 'import', - ], - [ - 'access' => 'user,group', - 'icon' => self::getIconPath() . 'ModuleConfigurations.svg', - 'labels' => self::getLanguagePath() . 'locallang_mod_configurations.xlf', - ] - ); - ExtensionUtility::registerModule( - self::EXTENSION_NAME, - 'thuecat', - 'imports', - '', - [ - ImportController::class => 'index,import', - ], - [ - 'access' => 'user,group', - 'icon' => self::getIconPath() . 'ModuleImports.svg', - 'labels' => self::getLanguagePath() . 'locallang_mod_imports.xlf', - ] - ); - } - public static function registerConfig(): void { self::addCaching(); self::addContentElements(); self::addPageTypes(); - self::addIcons(); } public static function getIconPath(): string @@ -129,28 +79,20 @@ class Extension private static function addPageTypes(): void { + $registry = GeneralUtility::makeInstance(PageDoktypeRegistry::class); + $registry->add( + self::PAGE_DOKTYPE_TOURIST_ATTRACTION, + [ + 'type' => 'web', + 'allowedTables' => '*', + ] + ); + ExtensionManagementUtility::addUserTSConfig( "@import 'EXT:" . self::EXTENSION_KEY . "/Configuration/TSconfig/User/All.tsconfig'" ); } - private static function addIcons(): void - { - $iconFiles = GeneralUtility::getFilesInDir(GeneralUtility::getFileAbsFileName(self::getIconPath())); - if (is_array($iconFiles) === false) { - return; - } - - $iconRegistry = GeneralUtility::makeInstance(IconRegistry::class); - foreach ($iconFiles as $iconFile) { - $iconRegistry->registerIcon( - str_replace('.svg', '', $iconFile), - SvgIconProvider::class, - ['source' => self::getIconPath() . $iconFile] - ); - } - } - private static function addCaching(): void { $cacheIdentifier = 'thuecat_fetchdata'; diff --git a/Classes/Frontend/DataProcessing/ResolveEntities.php b/Classes/Frontend/DataProcessing/ResolveEntities.php index 2ae37d0..3d7797a 100644 --- a/Classes/Frontend/DataProcessing/ResolveEntities.php +++ b/Classes/Frontend/DataProcessing/ResolveEntities.php @@ -33,27 +33,12 @@ use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController; class ResolveEntities implements DataProcessorInterface { - /** - * @var ConnectionPool - */ - private $connectionPool; - - /** - * @var DataMapper - */ - private $dataMapper; - - /** - * @var TypoScriptFrontendController - */ - private $tsfe; + private readonly TypoScriptFrontendController $tsfe; public function __construct( - ConnectionPool $connectionPool, - DataMapper $dataMapper + private readonly ConnectionPool $connectionPool, + private readonly DataMapper $dataMapper ) { - $this->connectionPool = $connectionPool; - $this->dataMapper = $dataMapper; $this->tsfe = $GLOBALS['TSFE']; } @@ -67,9 +52,9 @@ class ResolveEntities implements DataProcessorInterface return $processedData; } - $as = (string) $cObj->stdWrapValue('as', $processorConfiguration, 'entities'); - $tableName = (string) $cObj->stdWrapValue('table', $processorConfiguration, ''); - $uids = (string) $cObj->stdWrapValue('uids', $processorConfiguration, ''); + $as = (string)$cObj->stdWrapValue('as', $processorConfiguration, 'entities'); + $tableName = (string)$cObj->stdWrapValue('table', $processorConfiguration, ''); + $uids = (string)$cObj->stdWrapValue('uids', $processorConfiguration, ''); $uids = GeneralUtility::intExplode(',', $uids); if ($uids === [] || $tableName === '') { @@ -93,14 +78,14 @@ class ResolveEntities implements DataProcessorInterface )); $rows = []; - foreach ($queryBuilder->execute() as $row) { + foreach ($queryBuilder->executeQuery()->iterateAssociative() as $row) { $row = $this->tsfe->sys_page->getLanguageOverlay($tableName, $row); if (is_array($row)) { $rows[] = $row; } } - usort($rows, function (array $rowA, array $rowB) use($uids) { + usort($rows, function (array $rowA, array $rowB) use ($uids) { return array_search($rowA['uid'], $uids) <=> array_search($rowB['uid'], $uids); }); diff --git a/Classes/Service/DateBasedFilter/FilterBasedOnTypo3Context.php b/Classes/Service/DateBasedFilter/FilterBasedOnTypo3Context.php index 1671cb7..24b4a2a 100644 --- a/Classes/Service/DateBasedFilter/FilterBasedOnTypo3Context.php +++ b/Classes/Service/DateBasedFilter/FilterBasedOnTypo3Context.php @@ -23,20 +23,15 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Service\DateBasedFilter; +use DateTimeImmutable; use TYPO3\CMS\Core\Context\Context; use WerkraumMedia\ThueCat\Service\DateBasedFilter; class FilterBasedOnTypo3Context implements DateBasedFilter { - /** - * @var Context - */ - private $context; - public function __construct( - Context $context + private readonly Context $context ) { - $this->context = $context; } /** @@ -48,9 +43,9 @@ class FilterBasedOnTypo3Context implements DateBasedFilter array $listToFilter, callable $provideDate ): array { - $referenceDate = $this->context->getPropertyFromAspect('date', 'full', new \DateTimeImmutable()); + $referenceDate = $this->context->getPropertyFromAspect('date', 'full', new DateTimeImmutable()); - return array_filter($listToFilter, function($elementToFilter) use ($referenceDate, $provideDate) { + return array_filter($listToFilter, function ($elementToFilter) use ($referenceDate, $provideDate) { $objectDate = $provideDate($elementToFilter); return $objectDate === null || $objectDate >= $referenceDate; }); diff --git a/Classes/Typo3/Extbase/DataMapping/AfterObjectThawedHandler.php b/Classes/Typo3/Extbase/DataMapping/AfterObjectThawedHandler.php index e977729..a182ca0 100644 --- a/Classes/Typo3/Extbase/DataMapping/AfterObjectThawedHandler.php +++ b/Classes/Typo3/Extbase/DataMapping/AfterObjectThawedHandler.php @@ -36,22 +36,10 @@ use WerkraumMedia\ThueCat\Domain\Model\Frontend\Media; */ class AfterObjectThawedHandler { - /** - * @var FileRepository - */ - private $fileRepository; - - /** - * @var DataMapFactory - */ - private $dataMapFactory; - public function __construct( - FileRepository $fileRepository, - DataMapFactory $dataMapFactory + private readonly FileRepository $fileRepository, + private readonly DataMapFactory $dataMapFactory ) { - $this->fileRepository = $fileRepository; - $this->dataMapFactory = $dataMapFactory; } public function __invoke(AfterObjectThawedEvent $event): void @@ -89,7 +77,7 @@ class AfterObjectThawedHandler private function getTableNameForObject(Base $object): string { return $this->dataMapFactory - ->buildDataMap(get_class($object)) + ->buildDataMap($object::class) ->getTableName() ; } diff --git a/Classes/Updates/BackendModuleUserPermission.php b/Classes/Updates/BackendModuleUserPermission.php index e4cfca2..ff19e1c 100644 --- a/Classes/Updates/BackendModuleUserPermission.php +++ b/Classes/Updates/BackendModuleUserPermission.php @@ -25,19 +25,16 @@ namespace WerkraumMedia\ThueCat\Updates; use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Install\Attribute\UpgradeWizard; use TYPO3\CMS\Install\Updates\DatabaseUpdatedPrerequisite; use TYPO3\CMS\Install\Updates\UpgradeWizardInterface; +#[UpgradeWizard('thuecat_backendmoduleuserpermission_v12')] class BackendModuleUserPermission implements UpgradeWizardInterface { - /** - * @var ConnectionPool - */ - private $connectionPool; - - public function __construct() - { - $this->connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); + public function __construct( + private readonly ConnectionPool $connectionPool + ) { } public function getIdentifier(): string @@ -62,8 +59,9 @@ class BackendModuleUserPermission implements UpgradeWizardInterface $qb->count('*'); $qb->from('be_users'); $qb->where($qb->expr()->like('userMods', $qb->createNamedParameter('%site_ThuecatThuecat%'))); + $qb->orWhere($qb->expr()->like('userMods', $qb->createNamedParameter('%ThuecatThuecat%'))); - return $qb->execute()->fetchOne() > 0; + return $qb->executeQuery()->fetchOne() > 0; } public function executeUpdate(): bool @@ -73,14 +71,15 @@ class BackendModuleUserPermission implements UpgradeWizardInterface $qb->select('uid', 'userMods'); $qb->from('be_users'); $qb->where($qb->expr()->like('userMods', $qb->createNamedParameter('%site_ThuecatThuecat%'))); - $result = $qb->execute(); + $qb->orWhere($qb->expr()->like('userMods', $qb->createNamedParameter('%ThuecatThuecat%'))); + $result = $qb->executeQuery()->iterateAssociative(); foreach ($result as $backendUser) { $qb = $this->connectionPool->getQueryBuilderForTable('be_users'); $qb->update('be_users'); $qb->set('userMods', $this->updateMods($backendUser['userMods'])); $qb->where($qb->expr()->eq('uid', $qb->createNamedParameter($backendUser['uid']))); - $qb->execute(); + $qb->executeStatement(); } return true; @@ -90,11 +89,15 @@ class BackendModuleUserPermission implements UpgradeWizardInterface { $mods = GeneralUtility::trimExplode(',', $mods, true); - unset($mods[array_search('site_ThuecatThuecat', $mods)]); + unset( + $mods[array_search('site_ThuecatThuecat', $mods)], + $mods[array_search('ThuecatThuecat', $mods)], + $mods[array_search('ThuecatThuecat_ThuecatConfigurations', $mods)], + $mods[array_search('ThuecatThuecat_ThuecatImports', $mods)], + ); - $mods[] = 'ThuecatThuecat'; - $mods[] = 'ThuecatThuecat_ThuecatConfigurations'; - $mods[] = 'ThuecatThuecat_ThuecatImports'; + $mods[] = 'thuecat_configurations'; + $mods[] = 'thuecat_imports'; return implode(',', $mods); } @@ -105,9 +108,4 @@ class BackendModuleUserPermission implements UpgradeWizardInterface DatabaseUpdatedPrerequisite::class, ]; } - - public static function register(): void - { - $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'][self::class] = self::class; - } } diff --git a/Configuration/Backend/Modules.php b/Configuration/Backend/Modules.php new file mode 100644 index 0000000..05be5d2 --- /dev/null +++ b/Configuration/Backend/Modules.php @@ -0,0 +1,47 @@ + [ + 'icon' => Extension::getIconPath() . 'ModuleGroup.svg', + 'position' => [ + 'after' => 'web', + 'before' => 'file', + ], + 'labels' => 'LLL:EXT:thuecat/Resources/Private/Language/locallang_mod.xlf', + 'extensionName' => 'Thuecat', + ], + 'thuecat_configurations' => [ + 'parent' => 'thuecat_thuecat', + 'access' => 'user', + 'icon' => Extension::getIconPath() . 'ModuleConfigurations.svg', + 'labels' => 'LLL:EXT:thuecat/Resources/Private/Language/locallang_mod_configurations.xlf', + 'extensionName' => 'Thuecat', + 'controllerActions' => [ + ConfigurationController::class => [ + 'index', + ], + ImportController::class => [ + 'import', + ], + ], + ], + 'thuecat_imports' => [ + 'parent' => 'thuecat_thuecat', + 'access' => 'user', + 'icon' => Extension::getIconPath() . 'ModuleImports.svg', + 'labels' => 'LLL:EXT:thuecat/Resources/Private/Language/locallang_mod_imports.xlf', + 'extensionName' => 'Thuecat', + 'controllerActions' => [ + ImportController::class => [ + 'index', + 'import', + ], + ], + ], +]; diff --git a/Configuration/Extbase/Persistence/Classes.php b/Configuration/Extbase/Persistence/Classes.php index 33481e4..827a781 100644 --- a/Configuration/Extbase/Persistence/Classes.php +++ b/Configuration/Extbase/Persistence/Classes.php @@ -1,47 +1,62 @@ [ + Organisation::class => [ 'tableName' => 'tx_thuecat_organisation', ], - \WerkraumMedia\ThueCat\Domain\Model\Backend\Town::class => [ + Town::class => [ 'tableName' => 'tx_thuecat_town', ], - \WerkraumMedia\ThueCat\Domain\Model\Backend\TouristInformation::class => [ + TouristInformation::class => [ 'tableName' => 'tx_thuecat_tourist_information', ], - WerkraumMedia\ThueCat\Domain\Model\Backend\ParkingFacility::class => [ + ParkingFacility::class => [ 'tableName' => 'tx_thuecat_parking_facility', ], - \WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration::class => [ + ImportConfiguration::class => [ 'tableName' => 'tx_thuecat_import_configuration', ], - \WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLog::class => [ + ImportLog::class => [ 'tableName' => 'tx_thuecat_import_log', ], - \WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLogEntry::class => [ + ImportLogEntry::class => [ 'tableName' => 'tx_thuecat_import_log_entry', 'subclasses' => [ - 'savingEntity' => \WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLogEntry\SavingEntity::class, - 'mappingError' => \WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLogEntry\MappingError::class, + 'savingEntity' => SavingEntity::class, + 'mappingError' => MappingError::class, ], ], - \WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLogEntry\SavingEntity::class => [ + SavingEntity::class => [ 'tableName' => 'tx_thuecat_import_log_entry', 'recordType' => 'savingEntity', ], - \WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLogEntry\MappingError::class => [ + MappingError::class => [ 'tableName' => 'tx_thuecat_import_log_entry', 'recordType' => 'mappingError', ], - \WerkraumMedia\ThueCat\Domain\Model\Frontend\TouristAttraction::class => [ + + FrontendTouristAttraction::class => [ 'tableName' => 'tx_thuecat_tourist_attraction', ], - \WerkraumMedia\ThueCat\Domain\Model\Frontend\Town::class => [ + FrontendTown::class => [ 'tableName' => 'tx_thuecat_town', ], - WerkraumMedia\ThueCat\Domain\Model\Frontend\ParkingFacility::class => [ + FrontendParkingFacility::class => [ 'tableName' => 'tx_thuecat_parking_facility', ], ]; diff --git a/Configuration/Icons.php b/Configuration/Icons.php new file mode 100644 index 0000000..cbc9b7a --- /dev/null +++ b/Configuration/Icons.php @@ -0,0 +1,30 @@ + SvgIconProvider::class, + 'source' => Extension::getIconPath() . $iconFile, + ]; + } + + return $icons; +})(); diff --git a/Configuration/Services.php b/Configuration/Services.php index 7087a5e..c1819f5 100644 --- a/Configuration/Services.php +++ b/Configuration/Services.php @@ -6,17 +6,20 @@ namespace WerkraumMedia\ThueCat; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; +use WerkraumMedia\ThueCat\DependencyInjection\ConverterPass; +use WerkraumMedia\ThueCat\DependencyInjection\EntityPass; +use WerkraumMedia\ThueCat\DependencyInjection\UrlProvidersPass; use WerkraumMedia\ThueCat\Domain\Import\Entity\MapsToType; use WerkraumMedia\ThueCat\Domain\Import\Typo3Converter\Converter; use WerkraumMedia\ThueCat\Domain\Import\UrlProvider\UrlProvider; return function (ContainerConfigurator $container, ContainerBuilder $containerBuilder) { - $containerBuilder->registerForAutoconfiguration(UrlProvider::class)->addTag(DependencyInjection\UrlProvidersPass::TAG); - $containerBuilder->addCompilerPass(new DependencyInjection\UrlProvidersPass()); + $containerBuilder->registerForAutoconfiguration(UrlProvider::class)->addTag(UrlProvidersPass::TAG); + $containerBuilder->addCompilerPass(new UrlProvidersPass()); - $containerBuilder->registerForAutoconfiguration(Converter::class)->addTag(DependencyInjection\ConverterPass::TAG); - $containerBuilder->addCompilerPass(new DependencyInjection\ConverterPass()); + $containerBuilder->registerForAutoconfiguration(Converter::class)->addTag(ConverterPass::TAG); + $containerBuilder->addCompilerPass(new ConverterPass()); - $containerBuilder->registerForAutoconfiguration(MapsToType::class)->addTag(DependencyInjection\EntityPass::TAG); - $containerBuilder->addCompilerPass(new DependencyInjection\EntityPass()); + $containerBuilder->registerForAutoconfiguration(MapsToType::class)->addTag(EntityPass::TAG); + $containerBuilder->addCompilerPass(new EntityPass()); }; diff --git a/Configuration/TCA/Overrides/pages.php b/Configuration/TCA/Overrides/pages.php index 1eb4e24..87b1026 100644 --- a/Configuration/TCA/Overrides/pages.php +++ b/Configuration/TCA/Overrides/pages.php @@ -1,12 +1,18 @@ [ 'typeicon_classes' => [ 'contains-thuecat' => 'pages_module_thuecat', @@ -32,23 +38,23 @@ defined('TYPO3') or die(); ], ]); - \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTcaSelectItemGroup( + ExtensionManagementUtility::addTcaSelectItemGroup( $tableName, 'doktype', - \WerkraumMedia\ThueCat\Extension::TCA_SELECT_GROUP_IDENTIFIER, + Extension::TCA_SELECT_GROUP_IDENTIFIER, $languagePath . '.group' ); - \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTcaSelectItem( + ExtensionManagementUtility::addTcaSelectItem( $tableName, 'module', [ - 0 => $languagePath . '.module.thuecat', - 1 => 'thuecat', - 2 => 'pages_module_thuecat', + 'label' => $languagePath . '.module.thuecat', + 'value' => 'thuecat', + 'icon' => 'pages_module_thuecat', ] ); })( - \WerkraumMedia\ThueCat\Extension::EXTENSION_KEY, + Extension::EXTENSION_KEY, 'pages' ); diff --git a/Configuration/TCA/Overrides/pages_tourist_attraction.php b/Configuration/TCA/Overrides/pages_tourist_attraction.php index 576604e..fecca3a 100644 --- a/Configuration/TCA/Overrides/pages_tourist_attraction.php +++ b/Configuration/TCA/Overrides/pages_tourist_attraction.php @@ -1,12 +1,18 @@ [ 'typeicon_classes' => [ $doktype => $tableName . '_' . $pageIdentifier, @@ -54,19 +60,19 @@ defined('TYPO3') or die(); ], ]); - \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTcaSelectItem( + ExtensionManagementUtility::addTcaSelectItem( $tableName, 'doktype', [ - $languagePath, - $doktype, - \WerkraumMedia\ThueCat\Extension::getIconPath() . $tableName . '_' . $pageIdentifier . '.svg', - \WerkraumMedia\ThueCat\Extension::TCA_SELECT_GROUP_IDENTIFIER, + 'label' => $languagePath, + 'value' => $doktype, + 'icon' => Extension::getIconPath() . $tableName . '_' . $pageIdentifier . '.svg', + 'group' => Extension::TCA_SELECT_GROUP_IDENTIFIER, ] ); })( - \WerkraumMedia\ThueCat\Extension::EXTENSION_KEY, + Extension::EXTENSION_KEY, 'pages', - \WerkraumMedia\ThueCat\Extension::PAGE_DOKTYPE_TOURIST_ATTRACTION, + Extension::PAGE_DOKTYPE_TOURIST_ATTRACTION, 'tourist_attraction' ); diff --git a/Configuration/TCA/Overrides/sys_template.php b/Configuration/TCA/Overrides/sys_template.php index 379ee9f..9f6c0c7 100644 --- a/Configuration/TCA/Overrides/sys_template.php +++ b/Configuration/TCA/Overrides/sys_template.php @@ -1,19 +1,24 @@ [ 'typeicon_classes' => [ $cType => 'tt_content_' . $cType, @@ -48,18 +54,18 @@ defined('TYPO3') or die(); ], ]); - \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTcaSelectItem( + ExtensionManagementUtility::addTcaSelectItem( $tableName, 'CType', [ - $languagePath, - $cType, - \WerkraumMedia\ThueCat\Extension::getIconPath() . 'tt_content_' . $cType . '.svg', - \WerkraumMedia\ThueCat\Extension::TCA_SELECT_GROUP_IDENTIFIER, + 'label' => $languagePath, + 'value' => $cType, + 'icon' => Extension::getIconPath() . 'tt_content_' . $cType . '.svg', + 'group' => Extension::TCA_SELECT_GROUP_IDENTIFIER, ] ); })( - \WerkraumMedia\ThueCat\Extension::EXTENSION_KEY, + Extension::EXTENSION_KEY, 'tt_content', 'thuecat_tourist_attraction' ); diff --git a/Configuration/TCA/tx_thuecat_import_configuration.php b/Configuration/TCA/tx_thuecat_import_configuration.php index 1ef5ccd..b86db90 100644 --- a/Configuration/TCA/tx_thuecat_import_configuration.php +++ b/Configuration/TCA/tx_thuecat_import_configuration.php @@ -1,20 +1,23 @@ [ 'label' => 'title', - 'iconfile' => \WerkraumMedia\ThueCat\Extension::getIconPath() . $tableName . '.svg', + 'iconfile' => Extension::getIconPath() . $tableName . '.svg', 'type' => 'type', 'default_sortby' => 'title', 'tstamp' => 'tstamp', 'crdate' => 'crdate', - 'cruser_id' => 'cruser_id', 'title' => $languagePath, 'enablecolumns' => [ 'disabled' => 'disable', @@ -28,7 +31,8 @@ return (static function (string $extensionKey, string $tableName) { 'config' => [ 'type' => 'input', 'max' => 255, - 'eval' => 'required,trim,unique', + 'eval' => 'trim,unique', + 'required' => true, ], ], 'type' => [ @@ -38,16 +42,16 @@ return (static function (string $extensionKey, string $tableName) { 'renderType' => 'selectSingle', 'items' => [ [ - $languagePath . '.type.static', - 'static', + 'label' => $languagePath . '.type.static', + 'value' => 'static', ], [ - $languagePath . '.type.syncScope', - 'syncScope', + 'label' => $languagePath . '.type.syncScope', + 'value' => 'syncScope', ], [ - $languagePath . '.type.containsPlace', - 'containsPlace', + 'label' => $languagePath . '.type.containsPlace', + 'value' => 'containsPlace', ], ], ], @@ -67,9 +71,8 @@ return (static function (string $extensionKey, string $tableName) { ], 'tstamp' => [ 'config' => [ - 'type' => 'input', - 'renderType' => 'inputDateTime', - 'eval' => 'datetime', + 'type' => 'datetime', + 'format' => 'datetime', 'readOnly' => true, ], ], @@ -89,4 +92,4 @@ return (static function (string $extensionKey, string $tableName) { ], ], ]; -})(\WerkraumMedia\ThueCat\Extension::EXTENSION_KEY, 'tx_thuecat_import_configuration'); +})(Extension::EXTENSION_KEY, 'tx_thuecat_import_configuration'); diff --git a/Configuration/TCA/tx_thuecat_import_log.php b/Configuration/TCA/tx_thuecat_import_log.php index c679555..6104523 100644 --- a/Configuration/TCA/tx_thuecat_import_log.php +++ b/Configuration/TCA/tx_thuecat_import_log.php @@ -1,21 +1,24 @@ [ 'label' => 'crdate', 'label_alt' => 'configuration', 'label_alt_force' => true, - 'iconfile' => \WerkraumMedia\ThueCat\Extension::getIconPath() . $tableName . '.svg', + 'iconfile' => Extension::getIconPath() . $tableName . '.svg', 'default_sortby' => 'crdate desc', 'tstamp' => 'tstamp', 'crdate' => 'crdate', - 'cruser_id' => 'cruser_id', 'title' => $languagePath, 'enablecolumns' => [ 'disabled' => 'disable', @@ -44,9 +47,8 @@ return (static function (string $extensionKey, string $tableName) { 'crdate' => [ 'label' => $languagePath . '.crdate', 'config' => [ - 'type' => 'input', - 'renderType' => 'inputDateTime', - 'eval' => 'datetime', + 'type' => 'datetime', + 'format' => 'datetime', 'readOnly' => true, ], ], @@ -57,4 +59,4 @@ return (static function (string $extensionKey, string $tableName) { ], ], ]; -})(\WerkraumMedia\ThueCat\Extension::EXTENSION_KEY, 'tx_thuecat_import_log'); +})(Extension::EXTENSION_KEY, 'tx_thuecat_import_log'); diff --git a/Configuration/TCA/tx_thuecat_import_log_entry.php b/Configuration/TCA/tx_thuecat_import_log_entry.php index 3edf288..5ce7baa 100644 --- a/Configuration/TCA/tx_thuecat_import_log_entry.php +++ b/Configuration/TCA/tx_thuecat_import_log_entry.php @@ -1,22 +1,25 @@ [ 'label' => 'type', 'label_alt' => 'remote_id, table_name, record_uid', 'label_alt_force' => true, - 'iconfile' => \WerkraumMedia\ThueCat\Extension::getIconPath() . $tableName . '.svg', + 'iconfile' => Extension::getIconPath() . $tableName . '.svg', 'type' => 'type', 'default_sortby' => 'crdate', 'tstamp' => 'tstamp', 'crdate' => 'crdate', - 'cruser_id' => 'cruser_id', 'title' => $languagePath, 'enablecolumns' => [ 'disabled' => 'disable', @@ -32,12 +35,12 @@ return (static function (string $extensionKey, string $tableName) { 'renderType' => 'selectSingle', 'items' => [ [ - $languagePath . '.type.savingEntity', - 'savingEntity', + 'label' => $languagePath . '.type.savingEntity', + 'value' => 'savingEntity', ], [ - $languagePath . '.type.mappingError', - 'mappingError', + 'label' => $languagePath . '.type.mappingError', + 'value' => 'mappingError', ], ], ], @@ -56,8 +59,6 @@ return (static function (string $extensionKey, string $tableName) { 'renderType' => 'checkboxLabeledToggle', 'items' => [ [ - 0 => '', - 1 => '', 'labelChecked' => $languagePath . '.insertion.yes', 'labelUnchecked' => $languagePath . '.insertion.no', ], @@ -98,9 +99,8 @@ return (static function (string $extensionKey, string $tableName) { 'crdate' => [ 'label' => $languagePath . '.crdate', 'config' => [ - 'type' => 'input', - 'renderType' => 'inputDateTime', - 'eval' => 'datetime', + 'type' => 'datetime', + 'format' => 'datetime', 'readOnly' => true, ], ], @@ -120,4 +120,4 @@ return (static function (string $extensionKey, string $tableName) { ], ], ]; -})(\WerkraumMedia\ThueCat\Extension::EXTENSION_KEY, 'tx_thuecat_import_log_entry'); +})(Extension::EXTENSION_KEY, 'tx_thuecat_import_log_entry'); diff --git a/Configuration/TCA/tx_thuecat_organisation.php b/Configuration/TCA/tx_thuecat_organisation.php index 0d37b72..a5840af 100644 --- a/Configuration/TCA/tx_thuecat_organisation.php +++ b/Configuration/TCA/tx_thuecat_organisation.php @@ -1,18 +1,21 @@ [ 'label' => 'title', - 'iconfile' => \WerkraumMedia\ThueCat\Extension::getIconPath() . $tableName . '.svg', + 'iconfile' => Extension::getIconPath() . $tableName . '.svg', 'default_sortby' => 'title', 'tstamp' => 'tstamp', 'crdate' => 'crdate', - 'cruser_id' => 'cruser_id', 'title' => $languagePath, 'enablecolumns' => [ 'disabled' => 'disable', @@ -73,9 +76,8 @@ return (static function (string $extensionKey, string $tableName) { 'tstamp' => [ 'label' => $languagePath . '.tstamp', 'config' => [ - 'type' => 'input', - 'renderType' => 'inputDateTime', - 'eval' => 'datetime', + 'type' => 'datetime', + 'format' => 'datetime', 'readOnly' => true, ], ], @@ -88,4 +90,4 @@ return (static function (string $extensionKey, string $tableName) { ], ], ]; -})(\WerkraumMedia\ThueCat\Extension::EXTENSION_KEY, 'tx_thuecat_organisation'); +})(Extension::EXTENSION_KEY, 'tx_thuecat_organisation'); diff --git a/Configuration/TCA/tx_thuecat_parking_facility.php b/Configuration/TCA/tx_thuecat_parking_facility.php index 1d1e5bf..ec1cdb6 100644 --- a/Configuration/TCA/tx_thuecat_parking_facility.php +++ b/Configuration/TCA/tx_thuecat_parking_facility.php @@ -1,18 +1,21 @@ [ 'label' => 'title', - 'iconfile' => \WerkraumMedia\ThueCat\Extension::getIconPath() . $tableName . '.svg', + 'iconfile' => Extension::getIconPath() . $tableName . '.svg', 'default_sortby' => 'title', 'tstamp' => 'tstamp', 'crdate' => 'crdate', - 'cruser_id' => 'cruser_id', 'title' => $languagePath, 'enablecolumns' => [ 'disabled' => 'disable', @@ -28,17 +31,7 @@ return (static function (string $extensionKey, string $tableName) { '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, + 'type' => 'language', ], ], 'l18n_parent' => [ @@ -47,7 +40,12 @@ return (static function (string $extensionKey, string $tableName) { 'config' => [ 'type' => 'select', 'renderType' => 'selectSingle', - 'items' => [['', 0]], + 'items' => [ + [ + 'label' => '', + 'value' => 0, + ], + ], 'foreign_table' => $tableName, 'foreign_table_where' => 'AND ' . $tableName . '.pid=###CURRENT_PID### AND ' . $tableName . '.sys_language_uid IN (-1,0)', 'default' => 0, @@ -66,12 +64,10 @@ return (static function (string $extensionKey, string $tableName) { 'renderType' => 'checkboxToggle', 'items' => [ [ - 0 => '', - 1 => '', - 'invertStateDisplay' => true - ] + 'invertStateDisplay' => true, + ], ], - ] + ], ], 'title' => [ @@ -190,8 +186,8 @@ return (static function (string $extensionKey, string $tableName) { 'default' => '0', 'items' => [ [ - $languagePath . '.town.unkown', - 0, + 'label' => $languagePath . '.town.unkown', + 'value' => 0, ], ], 'readOnly' => true, @@ -207,8 +203,8 @@ return (static function (string $extensionKey, string $tableName) { 'default' => '0', 'items' => [ [ - $languagePath . '.managed_by.unkown', - 0, + 'label' => $languagePath . '.managed_by.unkown', + 'value' => 0, ], ], 'readOnly' => true, @@ -227,4 +223,4 @@ return (static function (string $extensionKey, string $tableName) { ], ], ]; -})(\WerkraumMedia\ThueCat\Extension::EXTENSION_KEY, 'tx_thuecat_parking_facility'); +})(Extension::EXTENSION_KEY, 'tx_thuecat_parking_facility'); diff --git a/Configuration/TCA/tx_thuecat_tourist_attraction.php b/Configuration/TCA/tx_thuecat_tourist_attraction.php index 5c6a48f..8a93e9f 100644 --- a/Configuration/TCA/tx_thuecat_tourist_attraction.php +++ b/Configuration/TCA/tx_thuecat_tourist_attraction.php @@ -1,18 +1,21 @@ [ 'label' => 'title', - 'iconfile' => \WerkraumMedia\ThueCat\Extension::getIconPath() . $tableName . '.svg', + 'iconfile' => Extension::getIconPath() . $tableName . '.svg', 'default_sortby' => 'title', 'tstamp' => 'tstamp', 'crdate' => 'crdate', - 'cruser_id' => 'cruser_id', 'title' => $languagePath, 'enablecolumns' => [ 'disabled' => 'disable', @@ -28,17 +31,7 @@ return (static function (string $extensionKey, string $tableName) { '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, + 'type' => 'language', ], ], 'l18n_parent' => [ @@ -47,7 +40,12 @@ return (static function (string $extensionKey, string $tableName) { 'config' => [ 'type' => 'select', 'renderType' => 'selectSingle', - 'items' => [['', 0]], + 'items' => [ + [ + 'label' => '', + 'value' => 0, + ], + ], 'foreign_table' => $tableName, 'foreign_table_where' => 'AND ' . $tableName . '.pid=###CURRENT_PID### AND ' . $tableName . '.sys_language_uid IN (-1,0)', 'default' => 0, @@ -269,8 +267,8 @@ return (static function (string $extensionKey, string $tableName) { 'default' => '0', 'items' => [ [ - $languagePath . '.town.unkown', - 0, + 'label' => $languagePath . '.town.unkown', + 'value' => 0, ], ], 'readOnly' => true, @@ -286,8 +284,8 @@ return (static function (string $extensionKey, string $tableName) { 'default' => '0', 'items' => [ [ - $languagePath . '.managed_by.unkown', - 0, + 'label' => $languagePath . '.managed_by.unkown', + 'value' => 0, ], ], 'readOnly' => true, @@ -298,12 +296,11 @@ return (static function (string $extensionKey, string $tableName) { 'l10n_mode' => 'exclude', 'config' => [ 'type' => 'group', - 'internal_type' => 'db', 'allowed' => 'tx_thuecat_parking_facility', 'foreign_table' => 'tx_thuecat_parking_facility', 'suggestOptions' => [ 'tx_thuecat_parking_facility' => [ - 'searchCondition' => 'sys_language_uid IN (0,-1)' + 'searchCondition' => 'sys_language_uid IN (0,-1)', ], ], 'readOnly' => true, @@ -313,11 +310,10 @@ return (static function (string $extensionKey, string $tableName) { 'editorial_images' => [ 'label' => $languagePath . '.editorial_images', 'l10n_mode' => 'exclude', - 'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig( - 'editorial_images', - [], - $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] - ), + 'config' => [ + 'type' => 'file', + 'allowed' => 'common-image-types', + ], ], ], 'palettes' => [ @@ -332,4 +328,4 @@ return (static function (string $extensionKey, string $tableName) { ], ], ]; -})(\WerkraumMedia\ThueCat\Extension::EXTENSION_KEY, 'tx_thuecat_tourist_attraction'); +})(Extension::EXTENSION_KEY, 'tx_thuecat_tourist_attraction'); diff --git a/Configuration/TCA/tx_thuecat_tourist_information.php b/Configuration/TCA/tx_thuecat_tourist_information.php index 4b0afbf..e8e041f 100644 --- a/Configuration/TCA/tx_thuecat_tourist_information.php +++ b/Configuration/TCA/tx_thuecat_tourist_information.php @@ -1,18 +1,21 @@ [ 'label' => 'title', - 'iconfile' => \WerkraumMedia\ThueCat\Extension::getIconPath() . $tableName . '.svg', + 'iconfile' => Extension::getIconPath() . $tableName . '.svg', 'default_sortby' => 'title', 'tstamp' => 'tstamp', 'crdate' => 'crdate', - 'cruser_id' => 'cruser_id', 'title' => $languagePath, 'enablecolumns' => [ 'disabled' => 'disable', @@ -52,8 +55,8 @@ return (static function (string $extensionKey, string $tableName) { 'default' => '0', 'items' => [ [ - $languagePath . '.town.unkown', - 0, + 'label' => $languagePath . '.town.unkown', + 'value' => 0, ], ], 'readOnly' => true, @@ -68,8 +71,8 @@ return (static function (string $extensionKey, string $tableName) { 'default' => '0', 'items' => [ [ - $languagePath . '.managed_by.unkown', - 0, + 'label' => $languagePath . '.managed_by.unkown', + 'value' => 0, ], ], 'readOnly' => true, @@ -82,4 +85,4 @@ return (static function (string $extensionKey, string $tableName) { ], ], ]; -})(\WerkraumMedia\ThueCat\Extension::EXTENSION_KEY, 'tx_thuecat_tourist_information'); +})(Extension::EXTENSION_KEY, 'tx_thuecat_tourist_information'); diff --git a/Configuration/TCA/tx_thuecat_town.php b/Configuration/TCA/tx_thuecat_town.php index 7cfe603..9eb4d8e 100644 --- a/Configuration/TCA/tx_thuecat_town.php +++ b/Configuration/TCA/tx_thuecat_town.php @@ -1,18 +1,21 @@ [ 'label' => 'title', - 'iconfile' => \WerkraumMedia\ThueCat\Extension::getIconPath() . $tableName . '.svg', + 'iconfile' => Extension::getIconPath() . $tableName . '.svg', 'default_sortby' => 'title', 'tstamp' => 'tstamp', 'crdate' => 'crdate', - 'cruser_id' => 'cruser_id', 'title' => $languagePath, 'enablecolumns' => [ 'disabled' => 'disable', @@ -51,8 +54,8 @@ return (static function (string $extensionKey, string $tableName) { 'foreign_table' => 'tx_thuecat_organisation', 'items' => [ [ - $languagePath . '.managed_by.unkown', - 0, + 'label' => $languagePath . '.managed_by.unkown', + 'value' => 0, ], ], 'readOnly' => true, @@ -74,4 +77,4 @@ return (static function (string $extensionKey, string $tableName) { ], ], ]; -})(\WerkraumMedia\ThueCat\Extension::EXTENSION_KEY, 'tx_thuecat_town'); +})(Extension::EXTENSION_KEY, 'tx_thuecat_town'); diff --git a/Documentation/Changelog/3.0.0.rst b/Documentation/Changelog/3.0.0.rst new file mode 100644 index 0000000..239b533 --- /dev/null +++ b/Documentation/Changelog/3.0.0.rst @@ -0,0 +1,32 @@ +3.0.0 +===== + +Breaking +-------- + +* Drop support for TYPO3 10.4 and 11.5. + +* Drop support for PHP 7.4 and 8.0. + +Features +-------- + +* Add support for TYPO3 12.4. + +* Add support for PHP 8.3. + +Fixes +----- + +Nothing + +Tasks +----- + +Nothing + +Deprecation +----------- + +Nothing + diff --git a/Documentation/Index.rst b/Documentation/Index.rst index 4a5ef2a..59bc1fa 100644 --- a/Documentation/Index.rst +++ b/Documentation/Index.rst @@ -20,5 +20,4 @@ Table of Contents Configuration Integration Changelog - Maintenance Sitemap diff --git a/Documentation/Maintenance.rst b/Documentation/Maintenance.rst index bc79526..14ca383 100644 --- a/Documentation/Maintenance.rst +++ b/Documentation/Maintenance.rst @@ -14,4 +14,4 @@ Those changes are documented so we know what to do once we drop an older version :glob: :reversed: - Maintenance/PHP/* + Maintenance/* diff --git a/Documentation/Maintenance/Extbase.rst b/Documentation/Maintenance/Extbase.rst new file mode 100644 index 0000000..338adc0 --- /dev/null +++ b/Documentation/Maintenance/Extbase.rst @@ -0,0 +1,15 @@ +.. _maintenanceExtbase: + +Extbase +======= + +PHPDoc Blocks with type hints mentioning `Necessary for Extbase/Symfony.` +------------------------------------------------------------------------- + +Those are necessary (at least with TYPO3 v12) because of Extbase and the underlying +Symfony component. + +Extbase uses the PHPDocExtractor first, before using the `ReflectionExtractor`, both part of Symfony property-info package. +The `ReflectionExtractor` will check the mutator followed by accessors prior checking the property itself. +Some of our properties have different return values by accessors than the stored value that is set to the property. +We therefore need to keep the PHPDoc block as this is checked first. diff --git a/Documentation/Maintenance/PHP/7.4.rst b/Documentation/Maintenance/PHP/7.4.rst deleted file mode 100644 index 2aba0df..0000000 --- a/Documentation/Maintenance/PHP/7.4.rst +++ /dev/null @@ -1,15 +0,0 @@ -PHP 7.4 -======= - -Changes that should happen once we drop PHP 7.4. - -Remove ``symfony/polyfill-php80`` dependency --------------------------------------------- - -We use PHP 8.0 functions within our code base (to not add legacy code and deprecations). - -One example is :file:`Classes/Domain/Import/Import.php` where we use ``str_ends_with()``. -We therefore added ``symfony/polyfill-php80`` as composer package to already make use of those functions. - -We can drop that package once we are at least on PHP 8.0. - diff --git a/Resources/Private/Templates/Backend/Configuration/Index.html b/Resources/Private/Templates/Backend/Configuration/Index.html index e88e28e..160692e 100644 --- a/Resources/Private/Templates/Backend/Configuration/Index.html +++ b/Resources/Private/Templates/Backend/Configuration/Index.html @@ -3,130 +3,138 @@ xmlns:f="http://typo3.org/ns/TYPO3/CMS/Backend/ViewHelpers" data-namespace-typo3-fluid="true"> -

{f:translate(id: 'module.overview.headline')}

+ {f:layout(name: 'Module')} - + +

{f:translate(id: 'module.overview.headline')}

-

- {f:translate(id: 'module.importConfigurations.headline')} - - {f:icon(identifier: 'actions-document-add')} - -

- - - {f:render(section: 'ImportConfigurations', arguments: {importConfigurations: importConfigurations})} - - - + +

+ {f:translate(id: 'module.importConfigurations.headline')} + - {f:translate( - id: 'module.importConfigurations.missing.text', - arguments: { - 0: "{f:uri.newRecord(table: 'tx_thuecat_import_configuration', pid: settings.newRecordPid.tx_thuecat_import_configuration)}" - } - ) -> f:format.raw()} - - - + {f:icon(identifier: 'actions-document-add')} + +

+ + + {f:render(section: 'ImportConfigurations', arguments: {importConfigurations: importConfigurations})} + + + + {f:translate( + id: 'module.importConfigurations.missing.text', + arguments: { + 0: "{f:uri.newRecord(table: 'tx_thuecat_import_configuration', pid: settings.newRecordPid.tx_thuecat_import_configuration)}" + } + ) -> f:format.raw()} + + + -

{f:translate(id: 'module.organisations.headline')}

- - - {f:render(section: 'Organisations', arguments: {organisations: organisations})} - - - {f:translate(id: 'module.organisations.missing.text')} - - +

{f:translate(id: 'module.organisations.headline')}

+ + + {f:render(section: 'Organisations', arguments: {organisations: organisations})} + + + {f:translate(id: 'module.organisations.missing.text')} + + +
- - - - - - - - - - - +
+
{f:translate(id: 'module.importConfigurations.title')}{f:translate(id: 'module.importConfigurations.lastChanged')}{f:translate(id: 'module.importConfigurations.lastImported')}{f:translate(id: 'module.actions')}
+ - - - - + + + + - - -
{importConfiguration.title}{importConfiguration.lastChanged -> f:format.date(format: 'd.m.Y H:i')} - - - {importConfiguration.lastImported -> f:format.date(format: 'd.m.Y H:i')} - - - {f:translate(id: 'module.importConfigurations.lastImported.never')} - - - - - {f:icon(identifier: 'actions-document-edit')} - - - {f:icon(identifier: 'actions-download')} - - {f:translate(id: 'module.importConfigurations.title')}{f:translate(id: 'module.importConfigurations.lastChanged')}{f:translate(id: 'module.importConfigurations.lastImported')}{f:translate(id: 'module.actions')}
+ + + + + {importConfiguration.title} + {importConfiguration.lastChanged -> f:format.date(format: 'd.m.Y H:i')} + + + + {importConfiguration.lastImported -> f:format.date(format: 'd.m.Y H:i')} + + + {f:translate(id: 'module.importConfigurations.lastImported.never')} + + + + + + {f:icon(identifier: 'actions-document-edit')} + + + {f:icon(identifier: 'actions-download')} + + + + + + +
- - - - - - - - - - - +
+
{f:translate(id: 'module.organisation.title')}{f:translate(id: 'module.organisation.towns')}{f:translate(id: 'module.organisation.lastImported')}{f:translate(id: 'module.actions')}
+ - - - - + + + + - - -
{organisation.title} - {f:render(section: 'Towns', arguments: {towns: organisation.managesTowns})} - {organisation.lastImported -> f:format.date(format: 'd.m.Y H:i')} - - {f:icon(identifier: 'actions-document-edit')} - - {f:translate(id: 'module.organisation.title')}{f:translate(id: 'module.organisation.towns')}{f:translate(id: 'module.organisation.lastImported')}{f:translate(id: 'module.actions')}
+ + + + + {organisation.title} + + {f:render(section: 'Towns', arguments: {towns: organisation.managesTowns})} + + {organisation.lastImported -> f:format.date(format: 'd.m.Y H:i')} + + + {f:icon(identifier: 'actions-document-edit')} + + + + + + +
diff --git a/Resources/Private/Templates/Backend/Import/Index.html b/Resources/Private/Templates/Backend/Import/Index.html index 29dfb60..14e1214 100644 --- a/Resources/Private/Templates/Backend/Import/Index.html +++ b/Resources/Private/Templates/Backend/Import/Index.html @@ -1,41 +1,47 @@ -

{f:translate(id: 'module.imports.headline')}

+ {f:layout(name: 'Module')} - + +

{f:translate(id: 'module.imports.headline')}

- - - {f:render(section: 'Imports', arguments: {imports: imports})} - - - - {f:translate(id: 'module.imports.missing.text')} - - - + + + + + {f:render(section: 'Imports', arguments: {imports: imports})} + + + + {f:translate(id: 'module.imports.missing.text')} + + + +
- - - - - - - - - - - - - {f:render(section: 'Import', arguments: {import: import})} - - -
{f:translate(id: 'module.imports.th.created')}{f:translate(id: 'module.imports.th.configuration')}{f:translate(id: 'module.imports.th.amountOfRecords')}{f:translate(id: 'module.imports.th.summary')}{f:translate(id: 'module.imports.th.errors')}
+
+ + + + + + + + + + + + + {f:render(section: 'Import', arguments: {import: import})} + + +
{f:translate(id: 'module.imports.th.created')}{f:translate(id: 'module.imports.th.configuration')}{f:translate(id: 'module.imports.th.amountOfRecords')}{f:translate(id: 'module.imports.th.summary')}{f:translate(id: 'module.imports.th.errors')}
+
diff --git a/Resources/Private/Templates/Frontend/ContentElement/TouristAttraction.html b/Resources/Private/Templates/Frontend/ContentElement/TouristAttraction.html index cee0610..b75f2fe 100644 --- a/Resources/Private/Templates/Frontend/ContentElement/TouristAttraction.html +++ b/Resources/Private/Templates/Frontend/ContentElement/TouristAttraction.html @@ -71,10 +71,10 @@
-

{f:translate(id: 'content.generalInformation', extensionName: 'Thuecat')}

@@ -109,6 +109,7 @@

{f:translate(id: 'content.sanitation', extensionName: 'Thuecat')}

+ sanitation {f:render(partial: 'Sanitation', arguments: {sanitation: entity.sanitation})}
diff --git a/Tests/Acceptance/Data/BasicDatabase.csv b/Tests/Acceptance/Data/BasicDatabase.csv deleted file mode 100644 index d99b3ad..0000000 --- a/Tests/Acceptance/Data/BasicDatabase.csv +++ /dev/null @@ -1,45 +0,0 @@ -pages -,uid,pid,doktype,slug,title -,1,0,4,/,Rootpage -,2,1,255,/storage,Storage -tx_thuecat_import_configuration -,uid,pid,title,type,configuration -,1,2,"Example Configuration",static," - - - - - 2 - - - - - - - - https://thuecat.org/resources/644315157726-jmww - - - - 0 - - - - - - https://thuecat.org/resources/072778761562-kwah - - - - 0 - - - - - - -", -"be_users" -,"uid","pid","tstamp","username","password","admin","disable","starttime","endtime","options","crdate","workspace_perms","deleted","TSconfig","lastlogin","workspace_id","db_mountpoints","usergroup","realName" -# password is "password" -,1,0,1366642540,"admin","$1$tCrlLajZ$C0sikFQQ3SWaFAZ1Me0Z/1",1,0,0,0,0,1366642540,1,0,,1371033743,0,0,0,"Klaus Admin" diff --git a/Tests/Acceptance/Data/BasicDatabase.php b/Tests/Acceptance/Data/BasicDatabase.php new file mode 100644 index 0000000..88e9cae --- /dev/null +++ b/Tests/Acceptance/Data/BasicDatabase.php @@ -0,0 +1,87 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1366642540', + 'username' => 'admin', + 'password' => '$1$tCrlLajZ$C0sikFQQ3SWaFAZ1Me0Z/1', + 'admin' => '1', + 'disable' => '0', + 'starttime' => '0', + 'endtime' => '0', + 'options' => '0', + 'crdate' => '1366642540', + 'workspace_perms' => '1', + 'deleted' => '0', + 'TSconfig' => null, + 'lastlogin' => '1371033743', + 'workspace_id' => '0', + ], + ], + 'pages' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'doktype' => PageRepository::DOKTYPE_DEFAULT, + 'slug' => '/', + 'title' => 'Rootpage', + ], + 1 => [ + 'uid' => '2', + 'pid' => '1', + 'doktype' => PageRepository::DOKTYPE_SYSFOLDER, + 'slug' => '/storage', + 'title' => 'Storage', + ], + ], + 'tx_thuecat_import_configuration' => [ + 0 => [ + 'uid' => '1', + 'pid' => '2', + 'title' => 'Example Configuration', + 'type' => 'static', + 'configuration' => ' + + + + + 2 + + + + + + + + https://thuecat.org/resources/644315157726-jmww + + + + 0 + + + + + + https://thuecat.org/resources/072778761562-kwah + + + + 0 + + + + + + + ', + ], + ], +]; diff --git a/Tests/Acceptance/Support/AcceptanceTester.php b/Tests/Acceptance/Support/AcceptanceTester.php index 8ac78d2..5ebb41e 100644 --- a/Tests/Acceptance/Support/AcceptanceTester.php +++ b/Tests/Acceptance/Support/AcceptanceTester.php @@ -29,6 +29,7 @@ use WerkraumMedia\ThueCat\Tests\Acceptance\Support\_generated\AcceptanceTesterAc /** * Inherited Methods + * * @method void wantToTest($text) * @method void wantTo($text) * @method void execute($callable) diff --git a/Tests/Acceptance/Support/Environment.php b/Tests/Acceptance/Support/Environment.php index 59433ba..6487710 100644 --- a/Tests/Acceptance/Support/Environment.php +++ b/Tests/Acceptance/Support/Environment.php @@ -23,6 +23,8 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Tests\Acceptance\Support; +use Codappix\Typo3PhpDatasets\TestingFramework; +use Codeception\Event\SuiteEvent; use TYPO3\TestingFramework\Core\Acceptance\Extension\BackendEnvironment; /** @@ -30,6 +32,8 @@ use TYPO3\TestingFramework\Core\Acceptance\Extension\BackendEnvironment; */ class Environment extends BackendEnvironment { + use TestingFramework; + protected $localConfig = [ 'coreExtensionsToLoad' => [ 'install', @@ -40,13 +44,17 @@ class Environment extends BackendEnvironment 'fluid', ], 'testExtensionsToLoad' => [ - 'typo3conf/ext/thuecat', - ], - 'csvDatabaseFixtures' => [ - __DIR__ . '/../Data/BasicDatabase.csv', + 'werkraummedia/thuecat', ], 'pathsToLinkInTestInstance' => [ '/../../../../../../Tests/Acceptance/Data/Sites/' => 'typo3conf/sites', ], ]; + + public function bootstrapTypo3Environment(SuiteEvent $suiteEvent) + { + parent::bootstrapTypo3Environment($suiteEvent); + + $this->importPHPDataSet(__DIR__ . '/../Data/BasicDatabase.php'); + } } diff --git a/Tests/Acceptance/Support/_generated/.gitignore b/Tests/Acceptance/Support/_generated/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/Tests/Acceptance/Support/_generated/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/Tests/Functional/AbstractImportTest.php b/Tests/Functional/AbstractImportTestCase.php similarity index 86% rename from Tests/Functional/AbstractImportTest.php rename to Tests/Functional/AbstractImportTestCase.php index 31d8075..a5c0b4a 100644 --- a/Tests/Functional/AbstractImportTest.php +++ b/Tests/Functional/AbstractImportTestCase.php @@ -23,17 +23,18 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Tests\Functional; -use TYPO3\CMS\Core\Localization\LanguageService; -use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase; +use Codappix\Typo3PhpDatasets\TestingFramework; +use TYPO3\CMS\Core\Localization\LanguageServiceFactory; -abstract class AbstractImportTest extends FunctionalTestCase +abstract class AbstractImportTestCase extends \TYPO3\TestingFramework\Core\Functional\FunctionalTestCase { + use TestingFramework; + /** * Whether to expect errors to be logged. * Will check for no errors if set to false. - * @var bool */ - protected $expectErrors = false; + protected bool $expectErrors = false; protected function setUp(): void { @@ -43,15 +44,12 @@ abstract class AbstractImportTest extends FunctionalTestCase 'extbase', 'frontend', ]); - $this->testExtensionsToLoad = array_merge($this->testExtensionsToLoad, [ - 'typo3conf/ext/thuecat/', + 'werkraummedia/thuecat/', ]); - $this->pathsToLinkInTestInstance = array_merge($this->pathsToLinkInTestInstance, [ 'typo3conf/ext/thuecat/Tests/Functional/Fixtures/Import/Sites/' => 'typo3conf/sites', ]); - $this->configurationToUseInTestInstance = array_merge($this->configurationToUseInTestInstance, [ 'LOG' => [ 'WerkraumMedia' => [ @@ -72,12 +70,11 @@ abstract class AbstractImportTest extends FunctionalTestCase ]); parent::setUp(); + GuzzleClientFaker::registerClient(); - - $this->setUpBackendUserFromFixture(1); - - $GLOBALS['LANG'] = $this->getContainer()->get(LanguageService::class); - + $this->importPHPDataSet(__DIR__ . '/Fixtures/Import/BackendUser.php'); + $this->setUpBackendUser(1); + $GLOBALS['LANG'] = $this->getContainer()->get(LanguageServiceFactory::class)->create('en_US'); foreach ($this->getLogFiles() as $logFile) { file_put_contents($logFile, ''); } @@ -88,9 +85,8 @@ abstract class AbstractImportTest extends FunctionalTestCase if ($this->expectErrors === true) { return; } - foreach ($this->getLogFiles() as $file) { - $this->assertSame( + self::assertSame( '', file_get_contents($file), 'The TYPO3 log file "' . $file . '" contained content while expecting to be empty.' @@ -103,10 +99,8 @@ abstract class AbstractImportTest extends FunctionalTestCase $this->expectErrors = false; unset($GLOBALS['LANG']); GuzzleClientFaker::tearDown(); - parent::tearDown(); } - /** * @return string[] */ diff --git a/Tests/Functional/Assertions/Import/ImportWithMultipleReferencesToSameObject.php b/Tests/Functional/Assertions/Import/ImportWithMultipleReferencesToSameObject.php new file mode 100644 index 0000000..b72404b --- /dev/null +++ b/Tests/Functional/Assertions/Import/ImportWithMultipleReferencesToSameObject.php @@ -0,0 +1,195 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'configuration' => '1', + ], + ], + 'tx_thuecat_import_log_entry' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'import_log' => '1', + 'record_uid' => '1', + 'table_name' => 'tx_thuecat_organisation', + 'insertion' => '1', + 'errors' => '[]', + ], + 1 => [ + 'uid' => '2', + 'pid' => '0', + 'import_log' => '1', + 'record_uid' => '1', + 'table_name' => 'tx_thuecat_town', + 'insertion' => '1', + 'errors' => '[]', + ], + 2 => [ + 'uid' => '3', + 'pid' => '0', + 'import_log' => '1', + 'record_uid' => '1', + 'table_name' => 'tx_thuecat_parking_facility', + 'insertion' => '1', + 'errors' => '[]', + ], + 3 => [ + 'uid' => '4', + 'pid' => '0', + 'import_log' => '1', + 'record_uid' => '2', + 'table_name' => 'tx_thuecat_parking_facility', + 'insertion' => '0', + 'errors' => '[]', + ], + 4 => [ + 'uid' => '5', + 'pid' => '0', + 'import_log' => '1', + 'record_uid' => '3', + 'table_name' => 'tx_thuecat_parking_facility', + 'insertion' => '0', + 'errors' => '[]', + ], + 5 => [ + 'uid' => '6', + 'pid' => '0', + 'import_log' => '1', + 'record_uid' => '1', + 'table_name' => 'tx_thuecat_tourist_attraction', + 'insertion' => '1', + 'errors' => '[]', + ], + 6 => [ + 'uid' => '7', + 'pid' => '0', + 'import_log' => '1', + 'record_uid' => '2', + 'table_name' => 'tx_thuecat_tourist_attraction', + 'insertion' => '0', + 'errors' => '[]', + ], + 7 => [ + 'uid' => '8', + 'pid' => '0', + 'import_log' => '1', + 'record_uid' => '3', + 'table_name' => 'tx_thuecat_tourist_attraction', + 'insertion' => '1', + 'errors' => '[]', + ], + 8 => [ + 'uid' => '9', + 'pid' => '0', + 'import_log' => '1', + 'record_uid' => '4', + 'table_name' => 'tx_thuecat_tourist_attraction', + 'insertion' => '0', + 'errors' => '[]', + ], + 9 => [ + 'uid' => '10', + 'pid' => '0', + 'import_log' => '1', + 'record_uid' => '5', + 'table_name' => 'tx_thuecat_tourist_attraction', + 'insertion' => '0', + 'errors' => '[]', + ], + ], + 'tx_thuecat_organisation' => [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'remote_id' => 'https://thuecat.org/resources/018132452787-ngbe', + 'title' => 'Erfurt Tourismus und Marketing GmbH', + ], + ], + 'tx_thuecat_town' => [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'remote_id' => 'https://thuecat.org/resources/043064193523-jcyt', + 'title' => 'Erfurt', + 'managed_by' => '1', + ], + ], + 'tx_thuecat_parking_facility' => [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'sys_language_uid' => '0', + 'remote_id' => 'https://thuecat.org/resources/396420044896-drzt', + 'title' => 'Parkhaus Domplatz', + 'managed_by' => '1', + ], + 1 => [ + 'uid' => '2', + 'pid' => '10', + 'sys_language_uid' => '1', + 'remote_id' => 'https://thuecat.org/resources/396420044896-drzt', + 'title' => 'Car park Domplatz', + 'managed_by' => '1', + ], + 2 => [ + 'uid' => '3', + 'pid' => '10', + 'sys_language_uid' => '2', + 'remote_id' => 'https://thuecat.org/resources/396420044896-drzt', + 'title' => 'Parking Domplatz', + 'managed_by' => '1', + ], + ], + 'tx_thuecat_tourist_attraction' => [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'sys_language_uid' => '0', + 'remote_id' => 'https://thuecat.org/resources/835224016581-dara', + 'title' => 'Dom St. Marien', + 'managed_by' => '1', + 'town' => '1', + ], + 1 => [ + 'uid' => '2', + 'pid' => '10', + 'sys_language_uid' => '1', + 'remote_id' => 'https://thuecat.org/resources/835224016581-dara', + 'title' => 'Cathedral of St. Mary', + 'managed_by' => '1', + 'town' => '1', + ], + 2 => [ + 'uid' => '3', + 'pid' => '10', + 'sys_language_uid' => '0', + 'remote_id' => 'https://thuecat.org/resources/165868194223-zmqf', + 'title' => 'Alte Synagoge', + 'managed_by' => '1', + 'town' => '1', + ], + 3 => [ + 'uid' => '4', + 'pid' => '10', + 'sys_language_uid' => '1', + 'remote_id' => 'https://thuecat.org/resources/165868194223-zmqf', + 'title' => 'Old Synagogue', + 'managed_by' => '1', + 'town' => '1', + ], + 4 => [ + 'uid' => '5', + 'pid' => '10', + 'sys_language_uid' => '2', + 'remote_id' => 'https://thuecat.org/resources/165868194223-zmqf', + 'title' => 'La vieille synagogue', + 'managed_by' => '1', + 'town' => '1', + ], + ], +]; diff --git a/Tests/Functional/Assertions/Import/ImportsContainsPlace.php b/Tests/Functional/Assertions/Import/ImportsContainsPlace.php new file mode 100644 index 0000000..fa570d3 --- /dev/null +++ b/Tests/Functional/Assertions/Import/ImportsContainsPlace.php @@ -0,0 +1,80 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'sys_language_uid' => '0', + 'remote_id' => 'https://thuecat.org/resources/835224016581-dara', + 'title' => 'Dom St. Marien', + ], + 1 => [ + 'uid' => '2', + 'pid' => '10', + 'sys_language_uid' => '1', + 'remote_id' => 'https://thuecat.org/resources/835224016581-dara', + 'title' => 'Cathedral of St. Mary', + ], + 2 => [ + 'uid' => '3', + 'pid' => '10', + 'sys_language_uid' => '0', + 'remote_id' => 'https://thuecat.org/resources/165868194223-zmqf', + 'title' => 'Alte Synagoge', + ], + 3 => [ + 'uid' => '4', + 'pid' => '10', + 'sys_language_uid' => '1', + 'remote_id' => 'https://thuecat.org/resources/165868194223-zmqf', + 'title' => 'Old Synagogue', + ], + 4 => [ + 'uid' => '5', + 'pid' => '10', + 'sys_language_uid' => '2', + 'remote_id' => 'https://thuecat.org/resources/165868194223-zmqf', + 'title' => 'La vieille synagogue', + ], + 5 => [ + 'uid' => '6', + 'pid' => '10', + 'sys_language_uid' => '0', + 'remote_id' => 'https://thuecat.org/resources/215230952334-yyno', + 'title' => 'Krämerbrücke', + ], + 6 => [ + 'uid' => '7', + 'pid' => '10', + 'sys_language_uid' => '1', + 'remote_id' => 'https://thuecat.org/resources/215230952334-yyno', + 'title' => 'Merchants\' Bridge', + ], + 7 => [ + 'uid' => '8', + 'pid' => '10', + 'sys_language_uid' => '2', + 'remote_id' => 'https://thuecat.org/resources/215230952334-yyno', + 'title' => 'Pont de l\'épicier', + ], + ], + 'tx_thuecat_organisation' => [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'remote_id' => 'https://thuecat.org/resources/018132452787-ngbe', + 'title' => 'Erfurt Tourismus und Marketing GmbH', + ], + ], + 'tx_thuecat_town' => [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'remote_id' => 'https://thuecat.org/resources/043064193523-jcyt', + 'title' => 'Erfurt', + ], + ], +]; diff --git a/Tests/Functional/Assertions/Import/ImportsFollowingRecordsInCaseOfAnMappingException.php b/Tests/Functional/Assertions/Import/ImportsFollowingRecordsInCaseOfAnMappingException.php new file mode 100644 index 0000000..a122900 --- /dev/null +++ b/Tests/Functional/Assertions/Import/ImportsFollowingRecordsInCaseOfAnMappingException.php @@ -0,0 +1,119 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'sys_language_uid' => '0', + 'remote_id' => 'https://thuecat.org/resources/165868194223-zmqf', + 'title' => 'Alte Synagoge', + ], + 1 => [ + 'uid' => '2', + 'pid' => '10', + 'sys_language_uid' => '1', + 'remote_id' => 'https://thuecat.org/resources/165868194223-zmqf', + 'title' => 'Old Synagogue', + ], + 2 => [ + 'uid' => '3', + 'pid' => '10', + 'sys_language_uid' => '2', + 'remote_id' => 'https://thuecat.org/resources/165868194223-zmqf', + 'title' => 'La vieille synagogue', + ], + ], + 'tx_thuecat_import_log' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'configuration' => '1', + 'log_entries' => '0', + ], + ], + 'tx_thuecat_import_log_entry' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'type' => 'mappingError', + 'import_log' => '1', + 'record_uid' => '0', + 'table_name' => '', + 'insertion' => '0', + 'errors' => '["Could not map incoming JSON-LD to target object: Failed to parse time string (18:00: 00) at position 5 (:): Unexpected character"]', + ], + 1 => [ + 'uid' => '2', + 'pid' => '0', + 'type' => 'mappingError', + 'import_log' => '1', + 'record_uid' => '0', + 'table_name' => '', + 'insertion' => '0', + 'errors' => '["Could not map incoming JSON-LD to target object: Failed to parse time string (18:00: 00) at position 5 (:): Unexpected character"]', + ], + 2 => [ + 'uid' => '3', + 'pid' => '0', + 'type' => 'mappingError', + 'import_log' => '1', + 'record_uid' => '0', + 'table_name' => '', + 'insertion' => '0', + 'errors' => '["Could not map incoming JSON-LD to target object: Failed to parse time string (18:00: 00) at position 5 (:): Unexpected character"]', + ], + 3 => [ + 'uid' => '4', + 'pid' => '0', + 'type' => 'savingEntity', + 'import_log' => '1', + 'record_uid' => '1', + 'table_name' => 'tx_thuecat_organisation', + 'insertion' => '1', + 'errors' => '[]', + ], + 4 => [ + 'uid' => '5', + 'pid' => '0', + 'type' => 'savingEntity', + 'import_log' => '1', + 'record_uid' => '1', + 'table_name' => 'tx_thuecat_town', + 'insertion' => '0', + 'errors' => '[]', + ], + 5 => [ + 'uid' => '6', + 'pid' => '0', + 'type' => 'savingEntity', + 'import_log' => '1', + 'record_uid' => '1', + 'table_name' => 'tx_thuecat_tourist_attraction', + 'insertion' => '1', + 'errors' => '[]', + ], + 6 => [ + 'uid' => '7', + 'pid' => '0', + 'type' => 'savingEntity', + 'import_log' => '1', + 'record_uid' => '2', + 'table_name' => 'tx_thuecat_tourist_attraction', + 'insertion' => '0', + 'errors' => '[]', + ], + 7 => [ + 'uid' => '8', + 'pid' => '0', + 'type' => 'savingEntity', + 'import_log' => '1', + 'record_uid' => '3', + 'table_name' => 'tx_thuecat_tourist_attraction', + 'insertion' => '0', + 'errors' => '[]', + ], + ], +]; diff --git a/Tests/Functional/Assertions/Import/ImportsFollowingRecordsInCaseOfAnMappingExceptionOldPhp.php b/Tests/Functional/Assertions/Import/ImportsFollowingRecordsInCaseOfAnMappingExceptionOldPhp.php new file mode 100644 index 0000000..d4a2fc1 --- /dev/null +++ b/Tests/Functional/Assertions/Import/ImportsFollowingRecordsInCaseOfAnMappingExceptionOldPhp.php @@ -0,0 +1,119 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'sys_language_uid' => '0', + 'remote_id' => 'https://thuecat.org/resources/165868194223-zmqf', + 'title' => 'Alte Synagoge', + ], + 1 => [ + 'uid' => '2', + 'pid' => '10', + 'sys_language_uid' => '1', + 'remote_id' => 'https://thuecat.org/resources/165868194223-zmqf', + 'title' => 'Old Synagogue', + ], + 2 => [ + 'uid' => '3', + 'pid' => '10', + 'sys_language_uid' => '2', + 'remote_id' => 'https://thuecat.org/resources/165868194223-zmqf', + 'title' => 'La vieille synagogue', + ], + ], + 'tx_thuecat_import_log' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'configuration' => '1', + 'log_entries' => '0', + ], + ], + 'tx_thuecat_import_log_entry' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'type' => 'mappingError', + 'import_log' => '1', + 'record_uid' => '0', + 'table_name' => '', + 'insertion' => '0', + 'errors' => '["Could not map incoming JSON-LD to target object: DateTimeImmutable::__construct(): Failed to parse time string (18:00: 00) at position 5 (:): Unexpected character"]', + ], + 1 => [ + 'uid' => '2', + 'pid' => '0', + 'type' => 'mappingError', + 'import_log' => '1', + 'record_uid' => '0', + 'table_name' => '', + 'insertion' => '0', + 'errors' => '["Could not map incoming JSON-LD to target object: DateTimeImmutable::__construct(): Failed to parse time string (18:00: 00) at position 5 (:): Unexpected character"]', + ], + 2 => [ + 'uid' => '3', + 'pid' => '0', + 'type' => 'mappingError', + 'import_log' => '1', + 'record_uid' => '0', + 'table_name' => '', + 'insertion' => '0', + 'errors' => '["Could not map incoming JSON-LD to target object: DateTimeImmutable::__construct(): Failed to parse time string (18:00: 00) at position 5 (:): Unexpected character"]', + ], + 3 => [ + 'uid' => '4', + 'pid' => '0', + 'type' => 'savingEntity', + 'import_log' => '1', + 'record_uid' => '1', + 'table_name' => 'tx_thuecat_organisation', + 'insertion' => '1', + 'errors' => '[]', + ], + 4 => [ + 'uid' => '5', + 'pid' => '0', + 'type' => 'savingEntity', + 'import_log' => '1', + 'record_uid' => '1', + 'table_name' => 'tx_thuecat_town', + 'insertion' => '0', + 'errors' => '[]', + ], + 5 => [ + 'uid' => '6', + 'pid' => '0', + 'type' => 'savingEntity', + 'import_log' => '1', + 'record_uid' => '1', + 'table_name' => 'tx_thuecat_tourist_attraction', + 'insertion' => '1', + 'errors' => '[]', + ], + 6 => [ + 'uid' => '7', + 'pid' => '0', + 'type' => 'savingEntity', + 'import_log' => '1', + 'record_uid' => '2', + 'table_name' => 'tx_thuecat_tourist_attraction', + 'insertion' => '0', + 'errors' => '[]', + ], + 7 => [ + 'uid' => '8', + 'pid' => '0', + 'type' => 'savingEntity', + 'import_log' => '1', + 'record_uid' => '3', + 'table_name' => 'tx_thuecat_tourist_attraction', + 'insertion' => '0', + 'errors' => '[]', + ], + ], +]; diff --git a/Tests/Functional/Assertions/Import/ImportsFreshOrganization.php b/Tests/Functional/Assertions/Import/ImportsFreshOrganization.php new file mode 100644 index 0000000..f8aa424 --- /dev/null +++ b/Tests/Functional/Assertions/Import/ImportsFreshOrganization.php @@ -0,0 +1,32 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '11', + 'remote_id' => 'https://thuecat.org/resources/018132452787-ngbe', + 'title' => 'Erfurt Tourismus und Marketing GmbH', + ], + ], + 'tx_thuecat_import_log' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'configuration' => '1', + ], + ], + 'tx_thuecat_import_log_entry' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'import_log' => '1', + 'record_uid' => '1', + 'table_name' => 'tx_thuecat_organisation', + 'insertion' => '1', + 'errors' => '[]', + ], + ], +]; diff --git a/Tests/Functional/Assertions/Import/ImportsSyncScope.php b/Tests/Functional/Assertions/Import/ImportsSyncScope.php new file mode 100644 index 0000000..68c14ee --- /dev/null +++ b/Tests/Functional/Assertions/Import/ImportsSyncScope.php @@ -0,0 +1,120 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'sys_language_uid' => '0', + 'l18n_parent' => '0', + 'l10n_source' => '0', + 'l10n_state' => null, + 'remote_id' => 'https://thuecat.org/resources/835224016581-dara', + 'title' => 'Dom St. Marien', + 'managed_by' => '1', + 'town' => '1', + 'address' => '{"street":"Domstufen 1","zip":"99084","city":"Erfurt","email":"dominformation@domberg-erfurt.de","phone":"+49 361 6461265","fax":"","geo":{"latitude":50.975955358589545,"longitude":11.023667024961856}}', + 'offers' => '[]', + ], + 1 => [ + 'uid' => '2', + 'pid' => '10', + 'sys_language_uid' => '1', + 'l18n_parent' => '1', + 'l10n_source' => '1', + 'l10n_state' => null, + 'remote_id' => 'https://thuecat.org/resources/835224016581-dara', + 'title' => 'Cathedral of St. Mary', + 'managed_by' => '1', + 'town' => '1', + 'address' => '{"street":"Domstufen 1","zip":"99084","city":"Erfurt","email":"dominformation@domberg-erfurt.de","phone":"+49 361 6461265","fax":"","geo":{"latitude":50.975955358589545,"longitude":11.023667024961856}}', + 'offers' => '[]', + ], + 2 => [ + 'uid' => '3', + 'pid' => '10', + 'sys_language_uid' => '0', + 'l18n_parent' => '0', + 'l10n_source' => '0', + 'l10n_state' => null, + 'remote_id' => 'https://thuecat.org/resources/165868194223-zmqf', + 'title' => 'Alte Synagoge', + 'managed_by' => '1', + 'town' => '1', + 'address' => '{"street":"Waagegasse 8","zip":"99084","city":"Erfurt","email":"altesynagoge@erfurt.de","phone":"+49 361 6551520","fax":"+49 361 6551669","geo":{"latitude":50.978765,"longitude":11.029133}}', + 'offers' => '[{"types":["GuidedTourOffer"],"title":"F\\u00fchrungen","description":"Immer samstags, um 11:15 Uhr findet eine \\u00f6ffentliche F\\u00fchrung durch das Museum statt. Dauer etwa 90 Minuten","prices":[{"title":"Erwachsene","description":"","price":8,"currency":"EUR","rule":"PerPerson"},{"title":"Erm\\u00e4\\u00dfigt","description":"als erm\\u00e4\\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt","price":5,"currency":"EUR","rule":"PerPerson"}]},{"types":["EntryOffer"],"title":"Eintritt","description":"Schulklassen und Kitagruppen im Rahmen des Unterrichts: Eintritt frei\\nAn jedem ersten Dienstag im Monat: Eintritt frei","prices":[{"title":"Erm\\u00e4\\u00dfigt","description":"als erm\\u00e4\\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt","price":5,"currency":"EUR","rule":"PerPerson"},{"title":"Familienkarte","description":"","price":17,"currency":"EUR","rule":"PerGroup"},{"title":"ErfurtCard","description":"","price":14.9,"currency":"EUR","rule":"PerPackage"},{"title":"Erwachsene","description":"","price":8,"currency":"EUR","rule":"PerPerson"}]}]', + ], + 3 => [ + 'uid' => '4', + 'pid' => '10', + 'sys_language_uid' => '1', + 'l18n_parent' => '3', + 'l10n_source' => '3', + 'l10n_state' => null, + 'remote_id' => 'https://thuecat.org/resources/165868194223-zmqf', + 'title' => 'Old Synagogue', + 'managed_by' => '1', + 'town' => '1', + 'address' => '{"street":"Waagegasse 8","zip":"99084","city":"Erfurt","email":"altesynagoge@erfurt.de","phone":"+49 361 6551520","fax":"+49 361 6551669","geo":{"latitude":50.978765,"longitude":11.029133}}', + 'offers' => '[{"types":["GuidedTourOffer"],"title":"","description":"","prices":[{"title":"","description":"","price":8,"currency":"EUR","rule":"PerPerson"},{"title":"","description":"","price":5,"currency":"EUR","rule":"PerPerson"}]},{"types":["EntryOffer"],"title":"","description":"","prices":[{"title":"","description":"","price":5,"currency":"EUR","rule":"PerPerson"},{"title":"","description":"","price":17,"currency":"EUR","rule":"PerGroup"},{"title":"","description":"","price":14.9,"currency":"EUR","rule":"PerPackage"},{"title":"","description":"","price":8,"currency":"EUR","rule":"PerPerson"}]}]', + ], + 4 => [ + 'uid' => '5', + 'pid' => '10', + 'sys_language_uid' => '2', + 'l18n_parent' => '3', + 'l10n_source' => '3', + 'l10n_state' => null, + 'remote_id' => 'https://thuecat.org/resources/165868194223-zmqf', + 'title' => 'La vieille synagogue', + 'managed_by' => '1', + 'town' => '1', + 'address' => '{"street":"Waagegasse 8","zip":"99084","city":"Erfurt","email":"altesynagoge@erfurt.de","phone":"+49 361 6551520","fax":"+49 361 6551669","geo":{"latitude":50.978765,"longitude":11.029133}}', + 'offers' => '[{"types":["GuidedTourOffer"],"title":"","description":"","prices":[{"title":"","description":"","price":8,"currency":"EUR","rule":"PerPerson"},{"title":"","description":"","price":5,"currency":"EUR","rule":"PerPerson"}]},{"types":["EntryOffer"],"title":"","description":"","prices":[{"title":"","description":"","price":5,"currency":"EUR","rule":"PerPerson"},{"title":"","description":"","price":17,"currency":"EUR","rule":"PerGroup"},{"title":"","description":"","price":14.9,"currency":"EUR","rule":"PerPackage"},{"title":"","description":"","price":8,"currency":"EUR","rule":"PerPerson"}]}]', + ], + 5 => [ + 'uid' => '6', + 'pid' => '10', + 'sys_language_uid' => '0', + 'l18n_parent' => '0', + 'l10n_source' => '0', + 'l10n_state' => null, + 'remote_id' => 'https://thuecat.org/resources/215230952334-yyno', + 'title' => 'Krämerbrücke', + 'managed_by' => '1', + 'town' => '1', + 'address' => '{"street":"Benediktsplatz 1","zip":"99084","city":"Erfurt","email":"service@erfurt-tourismus.de","phone":"+49 361 66 400","fax":"","geo":{"latitude":50.978772,"longitude":11.031622}}', + 'offers' => '[]', + ], + 6 => [ + 'uid' => '7', + 'pid' => '10', + 'sys_language_uid' => '1', + 'l18n_parent' => '6', + 'l10n_source' => '6', + 'l10n_state' => null, + 'remote_id' => 'https://thuecat.org/resources/215230952334-yyno', + 'title' => 'Merchants\' Bridge', + 'managed_by' => '1', + 'town' => '1', + 'address' => '{"street":"Benediktsplatz 1","zip":"99084","city":"Erfurt","email":"service@erfurt-tourismus.de","phone":"+49 361 66 400","fax":"","geo":{"latitude":50.978772,"longitude":11.031622}}', + 'offers' => '[]', + ], + 7 => [ + 'uid' => '8', + 'pid' => '10', + 'sys_language_uid' => '2', + 'l18n_parent' => '6', + 'l10n_source' => '6', + 'l10n_state' => null, + 'remote_id' => 'https://thuecat.org/resources/215230952334-yyno', + 'title' => 'Pont de l\'épicier', + 'managed_by' => '1', + 'town' => '1', + 'address' => '{"street":"Benediktsplatz 1","zip":"99084","city":"Erfurt","email":"service@erfurt-tourismus.de","phone":"+49 361 66 400","fax":"","geo":{"latitude":50.978772,"longitude":11.031622}}', + 'offers' => '[]', + ], + ], +]; diff --git a/Tests/Functional/Assertions/Import/ImportsTouristAttractionWithAccessibilitySpecification.php b/Tests/Functional/Assertions/Import/ImportsTouristAttractionWithAccessibilitySpecification.php new file mode 100644 index 0000000..6ba52a8 --- /dev/null +++ b/Tests/Functional/Assertions/Import/ImportsTouristAttractionWithAccessibilitySpecification.php @@ -0,0 +1,26 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'sys_language_uid' => '0', + 'l18n_parent' => '0', + 'l10n_source' => '0', + 'remote_id' => 'https://thuecat.org/resources/attraction-with-accessibility-specification', + 'title' => 'Attraktion mit accessibility specification', + ], + 1 => [ + 'uid' => '2', + 'pid' => '10', + 'sys_language_uid' => '1', + 'l18n_parent' => '1', + 'l10n_source' => '1', + 'remote_id' => 'https://thuecat.org/resources/attraction-with-accessibility-specification', + 'title' => 'Attraction with accessibility specification', + ], + ], +]; diff --git a/Tests/Functional/Assertions/Import/ImportsTouristAttractionWithMedia.php b/Tests/Functional/Assertions/Import/ImportsTouristAttractionWithMedia.php new file mode 100644 index 0000000..14a4a9a --- /dev/null +++ b/Tests/Functional/Assertions/Import/ImportsTouristAttractionWithMedia.php @@ -0,0 +1,22 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'remote_id' => 'https://thuecat.org/resources/attraction-with-media', + 'title' => 'Attraktion mit Bildern', + 'media' => '[{"mainImage":false,"type":"image","title":"Bild mit externem Autor","description":"","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5099196\\/Preview-1280x0\\/image","author":"GivenName FamilyName","copyrightYear":0,"license":{"type":"","author":""}},{"mainImage":false,"type":"image","title":"Bild mit author","description":"","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5099196\\/Preview-1280x0\\/image","author":"Full Name","copyrightYear":0,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":""}},{"mainImage":false,"type":"image","title":"Bild mit license author","description":"","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5099196\\/Preview-1280x0\\/image","author":"","copyrightYear":0,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":"Autor aus Lizenz"}},{"mainImage":false,"type":"image","title":"Bild mit author und license author","description":"","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5099196\\/Preview-1280x0\\/image","author":"Full Name","copyrightYear":0,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":"Autor aus Lizenz"}}]', + ], + 1 => [ + 'uid' => '2', + 'pid' => '10', + 'remote_id' => 'https://thuecat.org/resources/attraction-with-media', + 'title' => 'Attraction with media', + 'media' => '[{"mainImage":false,"type":"image","title":"Bild mit externem Autor","description":"","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5099196\\/Preview-1280x0\\/image","author":"GivenName FamilyName","copyrightYear":0,"license":{"type":"","author":""}},{"mainImage":false,"type":"image","title":"Bild mit author","description":"","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5099196\\/Preview-1280x0\\/image","author":"Full Name","copyrightYear":0,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":""}},{"mainImage":false,"type":"image","title":"Bild mit license author","description":"","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5099196\\/Preview-1280x0\\/image","author":"","copyrightYear":0,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":"Autor aus Lizenz"}},{"mainImage":false,"type":"image","title":"Bild mit author und license author","description":"","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5099196\\/Preview-1280x0\\/image","author":"Full Name","copyrightYear":0,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":"Autor aus Lizenz"}}]', + ], + ], +]; diff --git a/Tests/Functional/Assertions/Import/ImportsTouristAttractionsWithFilteredOpeningHours.php b/Tests/Functional/Assertions/Import/ImportsTouristAttractionsWithFilteredOpeningHours.php new file mode 100644 index 0000000..62d8aa2 --- /dev/null +++ b/Tests/Functional/Assertions/Import/ImportsTouristAttractionsWithFilteredOpeningHours.php @@ -0,0 +1,28 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'sys_language_uid' => '0', + 'l18n_parent' => '0', + 'l10n_source' => '0', + 'remote_id' => 'https://thuecat.org/resources/835224016581-dara', + 'title' => 'Dom St. Marien', + 'opening_hours' => '[{"opens":"13:00:00","closes":"17:00:00","from":{"date":"2050-11-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2050-04-30 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Sunday"]}]', + ], + 1 => [ + 'uid' => '2', + 'pid' => '10', + 'sys_language_uid' => '1', + 'l18n_parent' => '1', + 'l10n_source' => '1', + 'remote_id' => 'https://thuecat.org/resources/835224016581-dara', + 'title' => 'Cathedral of St. Mary', + 'opening_hours' => '[{"opens":"13:00:00","closes":"17:00:00","from":{"date":"2050-11-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2050-04-30 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Sunday"]}]', + ], + ], +]; diff --git a/Tests/Functional/Assertions/Import/ImportsTouristAttractionsWithRelations.php b/Tests/Functional/Assertions/Import/ImportsTouristAttractionsWithRelations.php new file mode 100644 index 0000000..aa987af --- /dev/null +++ b/Tests/Functional/Assertions/Import/ImportsTouristAttractionsWithRelations.php @@ -0,0 +1,425 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'sys_language_uid' => '0', + 'l18n_parent' => '0', + 'l10n_source' => '0', + 'l10n_state' => null, + 'remote_id' => 'https://thuecat.org/resources/835224016581-dara', + 'title' => 'Dom St. Marien', + 'description' => 'Über eine 70-stufige Freitreppe gelangt man vom Domplatz auf den Domberg mit seinen beiden ehemaligen Stiftskirchen. Der Dom, mit hochgotischem Chor, romanischem Turmbereich und spätgotischer Westhalle, ist Nachfolger des 724 von Rom veranlassten Sakralbaus. Er war die Hauptkirche des 742 von Bischof Bonifatius gegründeten Bistums Erfurt und während des Mittelalters bis in das frühe 19. Jahrhundert Sitz des Collegiatstifts St. Marien. 1507 erhielt Martin Luther hier die Priesterweihe. +Der ursprünglich romanische Kirchenbau wurde in der Zeit der Gotik entscheidend umgebaut. Besonders sehenswert sind die gotischen Chorfenster, das umfängliche Chorgestühl (14. Jhd.) sowie die romanischen Skulpturen einer thronenden Madonna und eines monumentalen Kerzenträgers im Innenraum. Berühmt ist er auch wegen der „Gloriosa“, der mit 2,56 m Durchmesser größten freischwingenden mittelalterlichen Glocke der Welt. +Das Ensemble von Dom und Severikirche bildet eine imposante Kulisse für die jährlich im Sommer stattfindenden DomStufen-Festspiele.', + 'managed_by' => '1', + 'town' => '1', + 'address' => '{"street":"Domstufen 1","zip":"99084","city":"Erfurt","email":"dominformation@domberg-erfurt.de","phone":"+49 361 6461265","fax":"","geo":{"latitude":50.975955358589545,"longitude":11.023667024961856}}', + 'offers' => '[]', + 'media' => '[{"mainImage":true,"type":"image","title":"Erfurt-Dom und Severikirche-beleuchtet.jpg","description":"","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5159216\\/Preview-1280x0\\/image","author":"","copyrightYear":2016,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":""}},{"mainImage":false,"type":"image","title":"Erfurt-Dom-und-Severikirche.jpg","description":"Sicht auf Dom St. Marien, St. Severikirche sowie die davor liegenden Klostergeb\\u00e4ude und einem Ausschnitt des Biergartens umgeben von einem d\\u00e4mmerungsverf\\u00e4rten Himmel","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5159186\\/Preview-1280x0\\/image","author":"","copyrightYear":2020,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":""}}]', + 'slogan' => '', + 'start_of_construction' => '', + 'sanitation' => 'Toilets,DisabledToilets', + 'other_service' => 'SeatingPossibilitiesRestArea,SouvenirShop', + 'museum_service' => '', + 'architectural_style' => 'GothicArt', + 'traffic_infrastructure' => 'BicycleLockersEnumMem,BusParkCoachParkEnumMem', + 'payment_accepted' => '', + 'digital_offer' => 'AugmentedReality', + 'photography' => 'Fotogenehmigung für innen', + 'pets_allowed' => 'false', + 'is_accessible_for_free' => 'true', + 'public_access' => 'true', + 'available_languages' => 'German,English', + 'distance_to_public_transport' => '350:MTR:Streetcar:CityBus', + 'parking_facility_near_by' => '1', + 'accessibility_specification' => '{}', + 'url' => 'http://www.dom-erfurt.de', + ], + 1 => [ + 'uid' => '2', + 'pid' => '10', + 'sys_language_uid' => '1', + 'l18n_parent' => '1', + 'l10n_source' => '1', + 'l10n_state' => null, + 'remote_id' => 'https://thuecat.org/resources/835224016581-dara', + 'title' => 'Cathedral of St. Mary', + 'description' => 'The late Gothic cathedral with its high-Gothic choir and Romanesque tower replaced the church built on this site for Bishop Boniface in 742. The central tower houses the "Gloriosa", the world’s largest medieval free-swinging bell.', + 'managed_by' => '1', + 'town' => '1', + 'address' => '{"street":"Domstufen 1","zip":"99084","city":"Erfurt","email":"dominformation@domberg-erfurt.de","phone":"+49 361 6461265","fax":"","geo":{"latitude":50.975955358589545,"longitude":11.023667024961856}}', + 'offers' => '[]', + 'media' => '[{"mainImage":true,"type":"image","title":"Erfurt-Dom und Severikirche-beleuchtet.jpg","description":"","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5159216\\/Preview-1280x0\\/image","author":"","copyrightYear":2016,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":""}},{"mainImage":false,"type":"image","title":"Erfurt-Dom-und-Severikirche.jpg","description":"Sicht auf Dom St. Marien, St. Severikirche sowie die davor liegenden Klostergeb\\u00e4ude und einem Ausschnitt des Biergartens umgeben von einem d\\u00e4mmerungsverf\\u00e4rten Himmel","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5159186\\/Preview-1280x0\\/image","author":"","copyrightYear":2020,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":""}}]', + 'slogan' => '', + 'start_of_construction' => '', + 'sanitation' => 'Toilets,DisabledToilets', + 'other_service' => 'SeatingPossibilitiesRestArea,SouvenirShop', + 'museum_service' => '', + 'architectural_style' => 'GothicArt', + 'traffic_infrastructure' => 'BicycleLockersEnumMem,BusParkCoachParkEnumMem', + 'payment_accepted' => '', + 'digital_offer' => 'AugmentedReality', + 'photography' => '', + 'pets_allowed' => 'false', + 'is_accessible_for_free' => 'true', + 'public_access' => 'true', + 'available_languages' => 'German,English', + 'distance_to_public_transport' => '350:MTR:Streetcar:CityBus', + 'parking_facility_near_by' => '1', + 'accessibility_specification' => '{}', + 'url' => 'http://www.dom-erfurt.de', + ], + 2 => [ + 'uid' => '3', + 'pid' => '10', + 'sys_language_uid' => '0', + 'l18n_parent' => '0', + 'l10n_source' => '0', + 'l10n_state' => null, + 'remote_id' => 'https://thuecat.org/resources/165868194223-zmqf', + 'title' => 'Alte Synagoge', + 'description' => 'Beispiel Beschreibung', + 'managed_by' => '1', + 'town' => '1', + 'address' => '{"street":"Waagegasse 8","zip":"99084","city":"Erfurt","email":"altesynagoge@erfurt.de","phone":"+49 361 6551520","fax":"+49 361 6551669","geo":{"latitude":50.978765,"longitude":11.029133}}', + 'offers' => '[{"types":["GuidedTourOffer"],"title":"F\\u00fchrungen","description":"Immer samstags, um 11:15 Uhr findet eine \\u00f6ffentliche F\\u00fchrung durch das Museum statt. Dauer etwa 90 Minuten","prices":[{"title":"Erwachsene","description":"","price":8,"currency":"EUR","rule":"PerPerson"},{"title":"Erm\\u00e4\\u00dfigt","description":"als erm\\u00e4\\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt","price":5,"currency":"EUR","rule":"PerPerson"}]},{"types":["EntryOffer"],"title":"Eintritt","description":"Schulklassen und Kitagruppen im Rahmen des Unterrichts: Eintritt frei\\nAn jedem ersten Dienstag im Monat: Eintritt frei","prices":[{"title":"Erm\\u00e4\\u00dfigt","description":"als erm\\u00e4\\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt","price":5,"currency":"EUR","rule":"PerPerson"},{"title":"Familienkarte","description":"","price":17,"currency":"EUR","rule":"PerGroup"},{"title":"ErfurtCard","description":"","price":14.9,"currency":"EUR","rule":"PerPackage"},{"title":"Erwachsene","description":"","price":8,"currency":"EUR","rule":"PerPerson"}]}]', + 'media' => '[{"mainImage":true,"type":"image","title":"Erfurt-Alte Synagoge","description":"Frontaler Blick auf die Hausfront\\/Hausfassade im Innenhof mit Zugang \\u00fcber die Waagegasse","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5099196\\/Preview-1280x0\\/image","author":"","copyrightYear":2009,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":"F:\\\\Bilddatenbank\\\\Museen und Ausstellungen\\\\Alte Synagoge"}}]', + 'slogan' => 'Highlight', + 'start_of_construction' => '11. Jh.', + 'sanitation' => 'Toilets,DisabledToilets,NappyChangingArea,FamilyAndChildFriendly', + 'other_service' => 'SeatingPossibilitiesRestArea,LockBoxes,SouvenirShop,BaggageStorage', + 'museum_service' => 'MuseumShop', + 'architectural_style' => 'GothicArt', + 'traffic_infrastructure' => 'ZeroSpecialTrafficInfrastructure', + 'payment_accepted' => 'CashPayment,EC', + 'digital_offer' => 'AudioGuide,VideoGuide', + 'photography' => 'ZeroPhotography', + 'pets_allowed' => 'Tiere sind im Gebäude nicht gestattet, ausgenommen sind Blinden- und Blindenbegleithunde.', + 'is_accessible_for_free' => 'false', + 'public_access' => 'true', + 'available_languages' => 'German,English,French', + 'distance_to_public_transport' => '200:MTR:CityBus', + 'parking_facility_near_by' => '', + 'accessibility_specification' => '{"accessibilityCertificationStatus":"AccessibilityChecked","certificationAccessibilityDeaf":"None","certificationAccessibilityMental":"None","certificationAccessibilityPartiallyDeaf":"None","certificationAccessibilityPartiallyVisual":"Info","certificationAccessibilityVisual":"None","certificationAccessibilityWalking":"Info","certificationAccessibilityWheelchair":"Info","accessibilitySearchCriteria":{"facilityAccessibilityWalking":["AllRoomsStepFreeAccess","HingedGrabRailToilet","LateralAccessibleToilet","StepFreeAccess","ToiletsPeopleWithDisabilities","NinetyCMWidthPassageWays","SpecialOffersWalkingImpairment","SpecialOffersWheelchairUsers"],"facilityAccessibilityVisual":["AssistanceDogsWelcome","VisuallyContrastingStepEdges","OffersInPictoralLanguage","SpecialOffersBlindPeople","SpecialOffersVisualImpairment","TactileOffers"],"facilityAccessibilityDeaf":["AudioInductionLoop","SpecialOffersHearingImpairment"],"facilityAccessibilityMental":["InformationWithPictogramsOrPictures"]},"shortDescriptionAccessibilityDeaf":"Deutsche Beschreibung von shortDescriptionAccessibilityDeaf","shortDescriptionAccessibilityMental":"Deutsche Beschreibung von shortDescriptionAccessibilityMental","shortDescriptionAccessibilityVisual":"Deutsche Beschreibung von shortDescriptionAccessibilityVisual","shortDescriptionAccessibilityWalking":"Deutsche Beschreibung von shortDescriptionAccessibilityWalking"}', + 'url' => 'http://www.alte-synagoge.erfurt.de', + ], + 3 => [ + 'uid' => '4', + 'pid' => '10', + 'sys_language_uid' => '1', + 'l18n_parent' => '3', + 'l10n_source' => '3', + 'l10n_state' => null, + 'remote_id' => 'https://thuecat.org/resources/165868194223-zmqf', + 'title' => 'Old Synagogue', + 'description' => 'The Old Synagogue is one of very few preserved medieval synagogues in Europe. Thanks to the extensive preservation of the original structure, it has a special place in the history of art and architecture and is among the most impressive and highly rated architectural monuments in Erfurt and Thuringia. The synagogue was constructed during the Middle Ages on the "via regia", one of the major European trade routes, at the heart of the historical old quarter very close to the Merchants Bridge and the town hall. Many parts of the structure still remain today, including all four thick outer walls, the Roman­esque gemel window, the Gothic rose window and the entrance to the synagogue room.', + 'managed_by' => '1', + 'town' => '1', + 'address' => '{"street":"Waagegasse 8","zip":"99084","city":"Erfurt","email":"altesynagoge@erfurt.de","phone":"+49 361 6551520","fax":"+49 361 6551669","geo":{"latitude":50.978765,"longitude":11.029133}}', + 'offers' => '[{"types":["GuidedTourOffer"],"title":"","description":"","prices":[{"title":"","description":"","price":8,"currency":"EUR","rule":"PerPerson"},{"title":"","description":"","price":5,"currency":"EUR","rule":"PerPerson"}]},{"types":["EntryOffer"],"title":"","description":"","prices":[{"title":"","description":"","price":5,"currency":"EUR","rule":"PerPerson"},{"title":"","description":"","price":17,"currency":"EUR","rule":"PerGroup"},{"title":"","description":"","price":14.9,"currency":"EUR","rule":"PerPackage"},{"title":"","description":"","price":8,"currency":"EUR","rule":"PerPerson"}]}]', + 'media' => '[{"mainImage":true,"type":"image","title":"Erfurt-Alte Synagoge","description":"Frontaler Blick auf die Hausfront\\/Hausfassade im Innenhof mit Zugang \\u00fcber die Waagegasse","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5099196\\/Preview-1280x0\\/image","author":"","copyrightYear":2009,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":"F:\\\\Bilddatenbank\\\\Museen und Ausstellungen\\\\Alte Synagoge"}}]', + 'slogan' => 'Highlight', + 'start_of_construction' => '11th century', + 'sanitation' => 'Toilets,DisabledToilets,NappyChangingArea,FamilyAndChildFriendly', + 'other_service' => 'SeatingPossibilitiesRestArea,LockBoxes,SouvenirShop,BaggageStorage', + 'museum_service' => 'MuseumShop', + 'architectural_style' => 'GothicArt', + 'traffic_infrastructure' => 'ZeroSpecialTrafficInfrastructure', + 'payment_accepted' => 'CashPayment,EC', + 'digital_offer' => 'AudioGuide,VideoGuide', + 'photography' => 'ZeroPhotography', + 'pets_allowed' => '', + 'is_accessible_for_free' => 'false', + 'public_access' => 'true', + 'available_languages' => 'German,English,French', + 'distance_to_public_transport' => '200:MTR:CityBus', + 'parking_facility_near_by' => '', + 'accessibility_specification' => '{"accessibilityCertificationStatus":"AccessibilityChecked","certificationAccessibilityDeaf":"None","certificationAccessibilityMental":"None","certificationAccessibilityPartiallyDeaf":"None","certificationAccessibilityPartiallyVisual":"Info","certificationAccessibilityVisual":"None","certificationAccessibilityWalking":"Info","certificationAccessibilityWheelchair":"Info","accessibilitySearchCriteria":{"facilityAccessibilityWalking":["AllRoomsStepFreeAccess","HingedGrabRailToilet","LateralAccessibleToilet","StepFreeAccess","ToiletsPeopleWithDisabilities","NinetyCMWidthPassageWays","SpecialOffersWalkingImpairment","SpecialOffersWheelchairUsers"],"facilityAccessibilityVisual":["AssistanceDogsWelcome","VisuallyContrastingStepEdges","OffersInPictoralLanguage","SpecialOffersBlindPeople","SpecialOffersVisualImpairment","TactileOffers"],"facilityAccessibilityDeaf":["AudioInductionLoop","SpecialOffersHearingImpairment"],"facilityAccessibilityMental":["InformationWithPictogramsOrPictures"]},"shortDescriptionAccessibilityDeaf":"English description of shortDescriptionAccessibilityDeaf","shortDescriptionAccessibilityMental":"English description of shortDescriptionAccessibilityMental","shortDescriptionAccessibilityVisual":"English description of shortDescriptionAccessibilityVisual","shortDescriptionAccessibilityWalking":"English description of shortDescriptionAccessibilityWalking"}', + 'url' => 'http://www.alte-synagoge.erfurt.de', + ], + 4 => [ + 'uid' => '5', + 'pid' => '10', + 'sys_language_uid' => '2', + 'l18n_parent' => '3', + 'l10n_source' => '3', + 'l10n_state' => null, + 'remote_id' => 'https://thuecat.org/resources/165868194223-zmqf', + 'title' => 'La vieille synagogue', + 'description' => 'La vieille synagogue (datant des années 1100) est la synagogue la plus vieille d’Europe totalement conservée, dans laquelle est exposé un trésor datant des 13/14èmes siècles avec une alliance juive unique et des écritures hébraïques (datant des 12ème, 13ème et 14èmes siècles). Après la redécouverte du Mikwé, Erfurt abrite des témoins uniques et fascinants d’une communauté juive médiévale.', + 'managed_by' => '1', + 'town' => '1', + 'address' => '{"street":"Waagegasse 8","zip":"99084","city":"Erfurt","email":"altesynagoge@erfurt.de","phone":"+49 361 6551520","fax":"+49 361 6551669","geo":{"latitude":50.978765,"longitude":11.029133}}', + 'offers' => '[{"types":["GuidedTourOffer"],"title":"","description":"","prices":[{"title":"","description":"","price":8,"currency":"EUR","rule":"PerPerson"},{"title":"","description":"","price":5,"currency":"EUR","rule":"PerPerson"}]},{"types":["EntryOffer"],"title":"","description":"","prices":[{"title":"","description":"","price":5,"currency":"EUR","rule":"PerPerson"},{"title":"","description":"","price":17,"currency":"EUR","rule":"PerGroup"},{"title":"","description":"","price":14.9,"currency":"EUR","rule":"PerPackage"},{"title":"","description":"","price":8,"currency":"EUR","rule":"PerPerson"}]}]', + 'media' => '[{"mainImage":true,"type":"image","title":"Erfurt-Alte Synagoge","description":"Frontaler Blick auf die Hausfront\\/Hausfassade im Innenhof mit Zugang \\u00fcber die Waagegasse","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5099196\\/Preview-1280x0\\/image","author":"","copyrightYear":2009,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":"F:\\\\Bilddatenbank\\\\Museen und Ausstellungen\\\\Alte Synagoge"}}]', + 'slogan' => 'Highlight', + 'start_of_construction' => '', + 'sanitation' => 'Toilets,DisabledToilets,NappyChangingArea,FamilyAndChildFriendly', + 'other_service' => 'SeatingPossibilitiesRestArea,LockBoxes,SouvenirShop,BaggageStorage', + 'museum_service' => 'MuseumShop', + 'architectural_style' => 'GothicArt', + 'traffic_infrastructure' => 'ZeroSpecialTrafficInfrastructure', + 'payment_accepted' => 'CashPayment,EC', + 'digital_offer' => 'AudioGuide,VideoGuide', + 'photography' => 'ZeroPhotography', + 'pets_allowed' => '', + 'is_accessible_for_free' => 'false', + 'public_access' => 'true', + 'available_languages' => 'German,English,French', + 'distance_to_public_transport' => '200:MTR:CityBus', + 'parking_facility_near_by' => '', + 'accessibility_specification' => '{"accessibilityCertificationStatus":"AccessibilityChecked","certificationAccessibilityDeaf":"None","certificationAccessibilityMental":"None","certificationAccessibilityPartiallyDeaf":"None","certificationAccessibilityPartiallyVisual":"Info","certificationAccessibilityVisual":"None","certificationAccessibilityWalking":"Info","certificationAccessibilityWheelchair":"Info","accessibilitySearchCriteria":{"facilityAccessibilityWalking":["AllRoomsStepFreeAccess","HingedGrabRailToilet","LateralAccessibleToilet","StepFreeAccess","ToiletsPeopleWithDisabilities","NinetyCMWidthPassageWays","SpecialOffersWalkingImpairment","SpecialOffersWheelchairUsers"],"facilityAccessibilityVisual":["AssistanceDogsWelcome","VisuallyContrastingStepEdges","OffersInPictoralLanguage","SpecialOffersBlindPeople","SpecialOffersVisualImpairment","TactileOffers"],"facilityAccessibilityDeaf":["AudioInductionLoop","SpecialOffersHearingImpairment"],"facilityAccessibilityMental":["InformationWithPictogramsOrPictures"]}}', + 'url' => 'http://www.alte-synagoge.erfurt.de', + ], + 5 => [ + 'uid' => '6', + 'pid' => '10', + 'sys_language_uid' => '0', + 'l18n_parent' => '0', + 'l10n_source' => '0', + 'l10n_state' => null, + 'remote_id' => 'https://thuecat.org/resources/215230952334-yyno', + 'title' => 'Krämerbrücke', + 'description' => 'Ein bekanntes Wahrzeichen Erfurts ist die Krämerbrücke, die längste bebaute und bewohnte Brücke Europas.Die Krämerbrücke wurde zu Beginn aus Holz und 1325 aus Stein erbaut. Zunächst war die 120 m lange Brücke mit 62 schmalen Häusern bebaut. Später wurden einige der Häuser auf nun mehr 32 zusammengefasst. An beiden Enden der Brücke standen zwei Brückenkopfkirchen. Heute existiert nur noch eine der beiden, die östlich gelegene Ägidienkirche.Auf der Krämerbrücke kann man in Galerien und Boutiquen sehr schön bummeln gehen. Man kann Thüringer Handwerksmeistern bei ihrer Arbeit über die Schulter schauen. Keramik, Porzellan und Holzschnitzereien, Blaudruck und Lauschaer Glas sind beliebte Souvenirs. Cafès, Weinhändler und Feinkostgeschäfte mit Thüringer Spezialitäten laden zum Verweilen ein.', + 'managed_by' => '1', + 'town' => '1', + 'address' => '{"street":"Benediktsplatz 1","zip":"99084","city":"Erfurt","email":"service@erfurt-tourismus.de","phone":"+49 361 66 400","fax":"","geo":{"latitude":50.978772,"longitude":11.031622}}', + 'offers' => '[]', + 'media' => '[{"mainImage":true,"type":"image","title":"Erfurt-Kraemerbruecke-11.jpg","description":"Kr\\u00e4merbr\\u00fccke in Erfurt","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/134362\\/Preview-1280x0\\/image","author":"Florian Trykowski","copyrightYear":2019,"license":{"type":"https:\\/\\/creativecommons.org\\/publicdomain\\/zero\\/1.0\\/deed.de","author":"https:\\/\\/home.ttgnet.de\\/ttg\\/projekte\\/10006\\/90136\\/Projektdokumente\\/Vergabe%20Rahmenvertrag%20Fotoproduktion"}},{"mainImage":false,"type":"image","title":"Erfurt-Kraemerbruecke.jpg","description":"Kr\\u00e4merbr\\u00fccke in Erfurt","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/134288\\/Preview-1280x0\\/image","author":"Florian Trykowski","copyrightYear":2019,"license":{"type":"https:\\/\\/creativecommons.org\\/publicdomain\\/zero\\/1.0\\/deed.de","author":"https:\\/\\/home.ttgnet.de\\/ttg\\/projekte\\/10006\\/90136\\/Projektdokumente\\/Vergabe%20Rahmenvertrag%20Fotoproduktion"}},{"mainImage":false,"type":"image","title":"Erfurt-Kraemerbruecke-13.jpg","description":"Ansicht der Kr\\u00e4merbr\\u00fccke, Erfurt","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/652340\\/Preview-1280x0\\/image","author":"Florian Trykowski","copyrightYear":2019,"license":{"type":"https:\\/\\/creativecommons.org\\/publicdomain\\/zero\\/1.0\\/deed.de","author":"https:\\/\\/home.ttgnet.de\\/ttg\\/projekte\\/10006\\/90136\\/Projektdokumente\\/Vergabe%20Rahmenvertrag%20Fotoproduktion"}}]', + 'slogan' => '', + 'start_of_construction' => '', + 'sanitation' => 'ZeroSanitation', + 'other_service' => 'Playground,SeatingPossibilitiesRestArea,SouvenirShop,PlayCornerOrPlayArea', + 'museum_service' => '', + 'architectural_style' => 'ZeroInformationArchitecturalStyle', + 'traffic_infrastructure' => 'BicycleLockersEnumMem', + 'payment_accepted' => '', + 'digital_offer' => 'ZeroDigitalOffer', + 'photography' => 'TakingPicturesPermitted', + 'pets_allowed' => 'true', + 'is_accessible_for_free' => 'true', + 'public_access' => 'true', + 'available_languages' => 'German,English,French', + 'distance_to_public_transport' => '250:MTR', + 'parking_facility_near_by' => '1,4', + 'accessibility_specification' => '{}', + 'url' => 'https://www.erfurt-tourismus.de/sehenswertes/kraemerbruecke', + ], + 6 => [ + 'uid' => '7', + 'pid' => '10', + 'sys_language_uid' => '1', + 'l18n_parent' => '6', + 'l10n_source' => '6', + 'l10n_state' => null, + 'remote_id' => 'https://thuecat.org/resources/215230952334-yyno', + 'title' => 'Merchants\' Bridge', + 'description' => 'Another Erfurt landmark is the Merchants\' Bridge (Krämerbrücke), the longest series of inhabited buildings on any bridge in Europe. The Merchants\' Bridge is Erfurts most interesting secular construction, initially in wood but rebuilt in stone in 1325. There were originally 62 narrow buildings along its 120-metre length, but subsequent redevelopment left just 32 buildings. Of what was once a pair of bridgehead churches, only the Church of St. Aegidius remains at the eastern end of the bridge today. The Merchants\' Bridge is lined with galleries, cafés and boutiques offering traditional crafts, Thuringian blue printed fabrics, hand-painted ceramics, handblown glassware, jewellery, wood carvings, antiques and delicious Thuringian specialities - perfect for browsing.', + 'managed_by' => '1', + 'town' => '1', + 'address' => '{"street":"Benediktsplatz 1","zip":"99084","city":"Erfurt","email":"service@erfurt-tourismus.de","phone":"+49 361 66 400","fax":"","geo":{"latitude":50.978772,"longitude":11.031622}}', + 'offers' => '[]', + 'media' => '[{"mainImage":true,"type":"image","title":"Erfurt-Kraemerbruecke-11.jpg","description":"Kr\\u00e4merbr\\u00fccke in Erfurt","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/134362\\/Preview-1280x0\\/image","author":"Florian Trykowski","copyrightYear":2019,"license":{"type":"https:\\/\\/creativecommons.org\\/publicdomain\\/zero\\/1.0\\/deed.de","author":"https:\\/\\/home.ttgnet.de\\/ttg\\/projekte\\/10006\\/90136\\/Projektdokumente\\/Vergabe%20Rahmenvertrag%20Fotoproduktion"}},{"mainImage":false,"type":"image","title":"Erfurt-Kraemerbruecke.jpg","description":"Kr\\u00e4merbr\\u00fccke in Erfurt","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/134288\\/Preview-1280x0\\/image","author":"Florian Trykowski","copyrightYear":2019,"license":{"type":"https:\\/\\/creativecommons.org\\/publicdomain\\/zero\\/1.0\\/deed.de","author":"https:\\/\\/home.ttgnet.de\\/ttg\\/projekte\\/10006\\/90136\\/Projektdokumente\\/Vergabe%20Rahmenvertrag%20Fotoproduktion"}},{"mainImage":false,"type":"image","title":"Erfurt-Kraemerbruecke-13.jpg","description":"Ansicht der Kr\\u00e4merbr\\u00fccke, Erfurt","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/652340\\/Preview-1280x0\\/image","author":"Florian Trykowski","copyrightYear":2019,"license":{"type":"https:\\/\\/creativecommons.org\\/publicdomain\\/zero\\/1.0\\/deed.de","author":"https:\\/\\/home.ttgnet.de\\/ttg\\/projekte\\/10006\\/90136\\/Projektdokumente\\/Vergabe%20Rahmenvertrag%20Fotoproduktion"}}]', + 'slogan' => '', + 'start_of_construction' => '', + 'sanitation' => 'ZeroSanitation', + 'other_service' => 'Playground,SeatingPossibilitiesRestArea,SouvenirShop,PlayCornerOrPlayArea', + 'museum_service' => '', + 'architectural_style' => 'ZeroInformationArchitecturalStyle', + 'traffic_infrastructure' => 'BicycleLockersEnumMem', + 'payment_accepted' => '', + 'digital_offer' => 'ZeroDigitalOffer', + 'photography' => 'TakingPicturesPermitted', + 'pets_allowed' => 'true', + 'is_accessible_for_free' => 'true', + 'public_access' => 'true', + 'available_languages' => 'German,English,French', + 'distance_to_public_transport' => '250:MTR', + 'parking_facility_near_by' => '1,4', + 'accessibility_specification' => '{}', + 'url' => 'https://www.erfurt-tourismus.de/sehenswertes/kraemerbruecke', + ], + 7 => [ + 'uid' => '8', + 'pid' => '10', + 'sys_language_uid' => '2', + 'l18n_parent' => '6', + 'l10n_source' => '6', + 'l10n_state' => null, + 'remote_id' => 'https://thuecat.org/resources/215230952334-yyno', + 'title' => 'Pont de l\'épicier', + 'description' => 'Le pont de l’épicier est un des symboles de la ville d’Erfurt, le plus grand pont habité en continu d’Europe. A l’origine, le pont de l’épicier faisait 120 m de long et comptait 62 maisons étroites, qui furent plus tard regroupées en 32 maisons. Sur le pont de l’épicier se trouvent des galeries et des petites échoppes proposant des étoffes à motifs bleu indigo de Thuringe, des céramiques peintes main, du verre de Lauscha, des bijoux et des sculptures en bois.', + 'managed_by' => '1', + 'town' => '1', + 'address' => '{"street":"Benediktsplatz 1","zip":"99084","city":"Erfurt","email":"service@erfurt-tourismus.de","phone":"+49 361 66 400","fax":"","geo":{"latitude":50.978772,"longitude":11.031622}}', + 'offers' => '[]', + 'media' => '[{"mainImage":true,"type":"image","title":"Erfurt-Kraemerbruecke-11.jpg","description":"Kr\\u00e4merbr\\u00fccke in Erfurt","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/134362\\/Preview-1280x0\\/image","author":"Florian Trykowski","copyrightYear":2019,"license":{"type":"https:\\/\\/creativecommons.org\\/publicdomain\\/zero\\/1.0\\/deed.de","author":"https:\\/\\/home.ttgnet.de\\/ttg\\/projekte\\/10006\\/90136\\/Projektdokumente\\/Vergabe%20Rahmenvertrag%20Fotoproduktion"}},{"mainImage":false,"type":"image","title":"Erfurt-Kraemerbruecke.jpg","description":"Kr\\u00e4merbr\\u00fccke in Erfurt","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/134288\\/Preview-1280x0\\/image","author":"Florian Trykowski","copyrightYear":2019,"license":{"type":"https:\\/\\/creativecommons.org\\/publicdomain\\/zero\\/1.0\\/deed.de","author":"https:\\/\\/home.ttgnet.de\\/ttg\\/projekte\\/10006\\/90136\\/Projektdokumente\\/Vergabe%20Rahmenvertrag%20Fotoproduktion"}},{"mainImage":false,"type":"image","title":"Erfurt-Kraemerbruecke-13.jpg","description":"Ansicht der Kr\\u00e4merbr\\u00fccke, Erfurt","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/652340\\/Preview-1280x0\\/image","author":"Florian Trykowski","copyrightYear":2019,"license":{"type":"https:\\/\\/creativecommons.org\\/publicdomain\\/zero\\/1.0\\/deed.de","author":"https:\\/\\/home.ttgnet.de\\/ttg\\/projekte\\/10006\\/90136\\/Projektdokumente\\/Vergabe%20Rahmenvertrag%20Fotoproduktion"}}]', + 'slogan' => '', + 'start_of_construction' => '', + 'sanitation' => 'ZeroSanitation', + 'other_service' => 'Playground,SeatingPossibilitiesRestArea,SouvenirShop,PlayCornerOrPlayArea', + 'museum_service' => '', + 'architectural_style' => 'ZeroInformationArchitecturalStyle', + 'traffic_infrastructure' => 'BicycleLockersEnumMem', + 'payment_accepted' => '', + 'digital_offer' => 'ZeroDigitalOffer', + 'photography' => 'TakingPicturesPermitted', + 'pets_allowed' => 'true', + 'is_accessible_for_free' => 'true', + 'public_access' => 'true', + 'available_languages' => 'German,English,French', + 'distance_to_public_transport' => '250:MTR', + 'parking_facility_near_by' => '1,4', + 'accessibility_specification' => '{}', + 'url' => 'https://www.erfurt-tourismus.de/sehenswertes/kraemerbruecke', + ], + ], + 'tx_thuecat_parking_facility' => [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'sys_language_uid' => '0', + 'l18n_parent' => '0', + 'l10n_source' => '0', + 'l10n_state' => null, + 'remote_id' => 'https://thuecat.org/resources/396420044896-drzt', + 'title' => 'Parkhaus Domplatz', + 'description' => 'Das Parkhaus Domplatz befindet sich unmittelbar unterhalb der Zitadelle Petersberg am nördlichen Rand des Domplatzes. Durch die zentrale Lage ist es ein idealer Ausgangspunkt für Stadtbummel und Erkundungen des Zentrums, des Petersbergs und des Andreasviertels.', + 'managed_by' => '1', + 'address' => '{"street":"Bechtheimer Str. 1","zip":"99084","city":"Erfurt","email":"info@stadtwerke-erfurt.de","phone":"+49 361 5640","fax":"","geo":{"latitude":50.977648905044,"longitude":11.022127985954299}}', + 'offers' => '[{"types":["ParkingFee"],"title":"","description":"","prices":[{"title":"","description":"","price":35,"currency":"EUR","rule":"PerCar"}]},{"types":["ParkingFee"],"title":"","description":"","prices":[{"title":"","description":"","price":1.5,"currency":"EUR","rule":"PerCar"}]},{"types":["ParkingFee"],"title":"","description":"","prices":[{"title":"","description":"","price":10,"currency":"EUR","rule":"PerCar"}]},{"types":["ParkingFee"],"title":"","description":"","prices":[{"title":"","description":"","price":50,"currency":"EUR","rule":"PerCar"}]}]', + 'media' => '[{"mainImage":true,"type":"image","title":"Erfurt-Parkhaus-Domplatz.jpg","description":"","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/6486108\\/Preview-1280x0\\/image","author":"Florian Trykowski","copyrightYear":2021,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":""}}]', + 'sanitation' => 'ZeroSanitation', + 'other_service' => 'ZeroOtherServiceEnumMem', + 'traffic_infrastructure' => 'ElectricVehicleCarChargingStationEnumMem', + 'payment_accepted' => '', + 'distance_to_public_transport' => '240:MTR:CityBus', + ], + 1 => [ + 'uid' => '2', + 'pid' => '10', + 'sys_language_uid' => '1', + 'l18n_parent' => '1', + 'l10n_source' => '1', + 'l10n_state' => null, + 'remote_id' => 'https://thuecat.org/resources/396420044896-drzt', + 'title' => 'Car park Domplatz', + 'description' => 'The Domplatz multi-storey car park is located directly below the Petersberg Citadel on the northern edge of the Domplatz. Its central location makes it an ideal starting point for strolling through the city and exploring the centre, the Petersberg and the Andreasviertel.', + 'managed_by' => '1', + 'address' => '{"street":"Bechtheimer Str. 1","zip":"99084","city":"Erfurt","email":"info@stadtwerke-erfurt.de","phone":"+49 361 5640","fax":"","geo":{"latitude":50.977648905044,"longitude":11.022127985954299}}', + 'offers' => '[{"types":["ParkingFee"],"title":"","description":"","prices":[{"title":"","description":"","price":35,"currency":"EUR","rule":"PerCar"}]},{"types":["ParkingFee"],"title":"","description":"","prices":[{"title":"","description":"","price":1.5,"currency":"EUR","rule":"PerCar"}]},{"types":["ParkingFee"],"title":"","description":"","prices":[{"title":"","description":"","price":10,"currency":"EUR","rule":"PerCar"}]},{"types":["ParkingFee"],"title":"","description":"","prices":[{"title":"","description":"","price":50,"currency":"EUR","rule":"PerCar"}]}]', + 'media' => '[{"mainImage":true,"type":"image","title":"Erfurt-Parkhaus-Domplatz.jpg","description":"","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/6486108\\/Preview-1280x0\\/image","author":"Florian Trykowski","copyrightYear":2021,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":""}}]', + 'sanitation' => 'ZeroSanitation', + 'other_service' => 'ZeroOtherServiceEnumMem', + 'traffic_infrastructure' => 'ElectricVehicleCarChargingStationEnumMem', + 'payment_accepted' => '', + 'distance_to_public_transport' => '240:MTR:CityBus', + ], + 2 => [ + 'uid' => '3', + 'pid' => '10', + 'sys_language_uid' => '2', + 'l18n_parent' => '1', + 'l10n_source' => '1', + 'l10n_state' => null, + 'remote_id' => 'https://thuecat.org/resources/396420044896-drzt', + 'title' => 'Parking Domplatz', + 'description' => 'Le parking à étages de la Domplatz est situé juste en dessous de la citadelle de Petersberg, sur le bord nord de la Domplatz. Son emplacement central en fait un point de départ idéal pour se promener dans la ville et explorer le centre, le Petersberg et l\'Andreasviertel.', + 'managed_by' => '1', + 'address' => '{"street":"Bechtheimer Str. 1","zip":"99084","city":"Erfurt","email":"info@stadtwerke-erfurt.de","phone":"+49 361 5640","fax":"","geo":{"latitude":50.977648905044,"longitude":11.022127985954299}}', + 'offers' => '[{"types":["ParkingFee"],"title":"","description":"","prices":[{"title":"","description":"","price":35,"currency":"EUR","rule":"PerCar"}]},{"types":["ParkingFee"],"title":"","description":"","prices":[{"title":"","description":"","price":1.5,"currency":"EUR","rule":"PerCar"}]},{"types":["ParkingFee"],"title":"","description":"","prices":[{"title":"","description":"","price":10,"currency":"EUR","rule":"PerCar"}]},{"types":["ParkingFee"],"title":"","description":"","prices":[{"title":"","description":"","price":50,"currency":"EUR","rule":"PerCar"}]}]', + 'media' => '[{"mainImage":true,"type":"image","title":"Erfurt-Parkhaus-Domplatz.jpg","description":"","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/6486108\\/Preview-1280x0\\/image","author":"Florian Trykowski","copyrightYear":2021,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":""}}]', + 'sanitation' => 'ZeroSanitation', + 'other_service' => 'ZeroOtherServiceEnumMem', + 'traffic_infrastructure' => 'ElectricVehicleCarChargingStationEnumMem', + 'payment_accepted' => '', + 'distance_to_public_transport' => '240:MTR:CityBus', + ], + 3 => [ + 'uid' => '4', + 'pid' => '10', + 'sys_language_uid' => '0', + 'l18n_parent' => '0', + 'l10n_source' => '0', + 'l10n_state' => null, + 'remote_id' => 'https://thuecat.org/resources/440055527204-ocar', + 'title' => 'Q-Park Anger 1 Parkhaus', + 'description' => 'Der Q-Park liegt direkt hinter dem Kaufhaus Anger 1 im Erfurter Stadtzentrum und ist über Juri-Gagarin-Ring/Meyfartstraße zu erreichen. Durch die direkte Anbindung an den Stadtring, ist das Parkhaus gut von außerhalb über Schnellstraßen und Autobahnen zu erreichen und befindet sich gleichzeitig im unmittelbaren modernen Zentrum Erfurts.', + 'managed_by' => '1', + 'address' => '{"street":"Anger 1","zip":"99084","city":"Erfurt","email":"servicecenter@q-park.de","phone":"+49 218 18190290","fax":"","geo":{"latitude":50.977999330565794,"longitude":11.037503264052475}}', + 'offers' => '[{"types":["ParkingFee"],"title":"","description":"","prices":[{"title":"","description":"","price":2.2,"currency":"EUR","rule":"PerCar"}]},{"types":["ParkingFee"],"title":"","description":"","prices":[{"title":"","description":"","price":1,"currency":"EUR","rule":"PerCar"}]},{"types":["ParkingFee"],"title":"","description":"","prices":[{"title":"","description":"","price":13,"currency":"EUR","rule":"PerCar"}]}]', + 'media' => '[{"mainImage":true,"type":"image","title":"Q-Park-Parkhaus-Anger1-Juri-Gagarin-Ring.JPG","description":"Stra\\u00dfenansicht des Parkhauses Q-Park am Kaufhaus Anger 1, schr\\u00e4g \\u00fcber den Juri-Gagarin-Ring","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5197164\\/Preview-1280x0\\/image","author":"Florian Trykowski","copyrightYear":2020,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":""}}]', + 'sanitation' => 'Toilets', + 'other_service' => 'ZeroOtherServiceEnumMem', + 'traffic_infrastructure' => '', + 'payment_accepted' => '', + 'distance_to_public_transport' => '120:MTR', + ], + 4 => [ + 'uid' => '5', + 'pid' => '10', + 'sys_language_uid' => '1', + 'l18n_parent' => '4', + 'l10n_source' => '4', + 'l10n_state' => null, + 'remote_id' => 'https://thuecat.org/resources/440055527204-ocar', + 'title' => 'Q-Park Anger 1 multi-storey car park', + 'description' => 'The Q-Park is located directly behind the department store Anger 1 in Erfurt\'s city centre and can be reached via Juri-Gagarin-Ring/Meyfartstraße.', + 'managed_by' => '1', + 'address' => '{"street":"Anger 1","zip":"99084","city":"Erfurt","email":"servicecenter@q-park.de","phone":"+49 218 18190290","fax":"","geo":{"latitude":50.977999330565794,"longitude":11.037503264052475}}', + 'offers' => '[{"types":["ParkingFee"],"title":"","description":"","prices":[{"title":"","description":"","price":2.2,"currency":"EUR","rule":"PerCar"}]},{"types":["ParkingFee"],"title":"","description":"","prices":[{"title":"","description":"","price":1,"currency":"EUR","rule":"PerCar"}]},{"types":["ParkingFee"],"title":"","description":"","prices":[{"title":"","description":"","price":13,"currency":"EUR","rule":"PerCar"}]}]', + 'media' => '[{"mainImage":true,"type":"image","title":"Q-Park-Parkhaus-Anger1-Juri-Gagarin-Ring.JPG","description":"Stra\\u00dfenansicht des Parkhauses Q-Park am Kaufhaus Anger 1, schr\\u00e4g \\u00fcber den Juri-Gagarin-Ring","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5197164\\/Preview-1280x0\\/image","author":"Florian Trykowski","copyrightYear":2020,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":""}}]', + 'sanitation' => 'Toilets', + 'other_service' => 'ZeroOtherServiceEnumMem', + 'traffic_infrastructure' => '', + 'payment_accepted' => '', + 'distance_to_public_transport' => '120:MTR', + ], + 5 => [ + 'uid' => '6', + 'pid' => '10', + 'sys_language_uid' => '2', + 'l18n_parent' => '4', + 'l10n_source' => '4', + 'l10n_state' => null, + 'remote_id' => 'https://thuecat.org/resources/440055527204-ocar', + 'title' => 'Q-Park Anger 1 parking à étages', + 'description' => 'Le Q-Park est situé directement derrière le grand magasin Anger 1 dans le centre-ville d\'Erfurt et peut être atteint par la Juri-Gagarin-Ring/Meyfartstraße.', + 'managed_by' => '1', + 'address' => '{"street":"Anger 1","zip":"99084","city":"Erfurt","email":"servicecenter@q-park.de","phone":"+49 218 18190290","fax":"","geo":{"latitude":50.977999330565794,"longitude":11.037503264052475}}', + 'offers' => '[{"types":["ParkingFee"],"title":"","description":"","prices":[{"title":"","description":"","price":2.2,"currency":"EUR","rule":"PerCar"}]},{"types":["ParkingFee"],"title":"","description":"","prices":[{"title":"","description":"","price":1,"currency":"EUR","rule":"PerCar"}]},{"types":["ParkingFee"],"title":"","description":"","prices":[{"title":"","description":"","price":13,"currency":"EUR","rule":"PerCar"}]}]', + 'media' => '[{"mainImage":true,"type":"image","title":"Q-Park-Parkhaus-Anger1-Juri-Gagarin-Ring.JPG","description":"Stra\\u00dfenansicht des Parkhauses Q-Park am Kaufhaus Anger 1, schr\\u00e4g \\u00fcber den Juri-Gagarin-Ring","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5197164\\/Preview-1280x0\\/image","author":"Florian Trykowski","copyrightYear":2020,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":""}}]', + 'sanitation' => 'Toilets', + 'other_service' => 'ZeroOtherServiceEnumMem', + 'traffic_infrastructure' => '', + 'payment_accepted' => '', + 'distance_to_public_transport' => '120:MTR', + ], + ], + 'tx_thuecat_organisation' => [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'remote_id' => 'https://thuecat.org/resources/018132452787-ngbe', + 'title' => 'Erfurt Tourismus und Marketing GmbH', + 'description' => 'Die Erfurt Tourismus & Marketing GmbH (ETMG) wurde 1997 als offizielle Organisation zur Tourismusförderung in der Landeshauptstadt Erfurt gegründet und nahm am 01.01.1998 die Geschäftstätigkeit auf. + +Zu den Aufgaben zählen die kommunale Tourismusförderung als wesentliches Instrument der Wirtschafts- und Stadtentwicklung der Landeshauptstadt Erfurt, die Positionierung der Stadt Erfurt auf dem nationalen und internationalen Tourismusmarkt als dynamische und sympathische Landeshauptstadt, attraktives Städtereiseziel und Tagungsstandort, die Vervollkommnung des touristischen Serviceangebotes entsprechend den Bedürfnissen der individuellen Gäste und der Tourismuswirtschaft und das Betreiben der Erfurt Tourist Information. + +Im Januar 2009 wurde das Marketing für die Landeshauptstadt Erfurt an die ETMG übertragen und neu geordnet. Die Hauptaufgaben im Stadtmarketing liegen darin, die Wahrnehmung der Stadt in folgenden Bereichen zu verstärken: traditionsreicher und innovativer Wirtschaftsstandort, lebendiger und kreativer Wissenschaftsstandort, attraktiver Wohnstandort mit Flair und Sportstandort mit exzellenten Bedingungen für Nachwuchs- und Spitzensportler. + +Gesellschafter: Stadt Erfurt + +Geschäftsführerin: Frau Dr. Carmen Hildebrandt + +Aufsichtsratsvorsitzender: Herr Dominik Kordon + +Mitarbeiter: ca. 30 Angestellte, 4 Auszubildende', + ], + ], +]; diff --git a/Tests/Functional/Assertions/Import/ImportsTouristAttractionsWithSpecialOpeningHours.php b/Tests/Functional/Assertions/Import/ImportsTouristAttractionsWithSpecialOpeningHours.php new file mode 100644 index 0000000..3be421f --- /dev/null +++ b/Tests/Functional/Assertions/Import/ImportsTouristAttractionsWithSpecialOpeningHours.php @@ -0,0 +1,28 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'sys_language_uid' => '0', + 'l18n_parent' => '0', + 'l10n_source' => '0', + 'remote_id' => 'https://thuecat.org/resources/835224016581-dara', + 'title' => 'Dom St. Marien', + 'special_opening_hours' => '[{"opens":"10:00:00","closes":"14:00:00","from":{"date":"2050-12-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2050-12-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Saturday"]}]', + ], + 1 => [ + 'uid' => '2', + 'pid' => '10', + 'sys_language_uid' => '1', + 'l18n_parent' => '1', + 'l10n_source' => '1', + 'remote_id' => 'https://thuecat.org/resources/835224016581-dara', + 'title' => 'Cathedral of St. Mary', + 'special_opening_hours' => '[{"opens":"10:00:00","closes":"14:00:00","from":{"date":"2050-12-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2050-12-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Saturday"]}]', + ], + ], +]; diff --git a/Tests/Functional/Assertions/Import/ImportsTouristInformationWithRelation.php b/Tests/Functional/Assertions/Import/ImportsTouristInformationWithRelation.php new file mode 100644 index 0000000..ed38a72 --- /dev/null +++ b/Tests/Functional/Assertions/Import/ImportsTouristInformationWithRelation.php @@ -0,0 +1,35 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'remote_id' => 'https://thuecat.org/resources/333039283321-xxwg', + 'title' => 'Erfurt Tourist Information', + 'description' => 'Direkt an der Krämerbrücke liegt die Erfurter Tourist Information. Nach einer Modernisierung im Frühjahr 2017 erstrahlt diese in neuem Glanz und ist auch technisch auf dem neuesten Stand. Hier erhalten Sie Stadtpläne, Broschüren zu Erfurt und originelle Souvenirs. Zudem bietet die Tourist Information vielfältige Stadtführungen und Rundfahrten mit Straßenbahn oder Bus sowie kompetente Beratung zu Hotels, Pensionen und Privatunterkünften.', + 'managed_by' => '1', + 'town' => '1', + ], + ], + 'tx_thuecat_town' => [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'remote_id' => 'https://thuecat.org/resources/043064193523-jcyt', + 'title' => 'Erfurt', + 'description' => 'Krämerbrücke, Dom, Alte Synagoge – die Thüringer Landeshauptstadt Erfurt hat viele Kulturschätze. Und ein wunderbar junges, studentisches Flair.Eine gute Mischung für alle, die beim Schlendern und Bummeln gerne Städte entdecken: Denn in Erfurt findet man einen wunderbaren mittelalterlichen Stadtkern – mit vielen netten Läden, Cafès und Restaurants. Urlauber wie Einheimische bummeln durch die Gassen der Altstadt, aus allen Ecken wispern Geschichte und alte Geschichten. Stolze historische Bügerhäuser bilden eine der schönsten Altstädte Europas, mittendrin das neugotische Rathaus aus den 1870er-Jahren am Fischmarkt, die spitztürmige St. Severikirche und der mächtige Dom, 1117 erstmals urkundlich erwähnt – auf seiner schier endlosen, kaskadenförmigen Freitreppe chillen Jung und Alt gern in der Abendsonne. Ehe sie weiter ziehen zum Tagesausklang in eine der coolen Kneipen und Bars (Tipp: Oma Lilo oder Cafè Hilgenfeld), in die Wein-Destille am benachbarten Petersberg oder in eins der lässigen Restaurants (Tipp: Mathilda oder Ballenberger), wo zum freundlichen Miteinander eine frische und moderne Küche serviert wird.In Erfurt pulsiert das Leben, lassen Sie sich einfach treiben. Von Ihrer Neugierde ...', + 'managed_by' => '1', + ], + ], + 'tx_thuecat_organisation' => [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'remote_id' => 'https://thuecat.org/resources/018132452787-ngbe', + 'title' => 'Erfurt Tourismus und Marketing GmbH', + ], + ], +]; diff --git a/Tests/Functional/Assertions/Import/ImportsTown.php b/Tests/Functional/Assertions/Import/ImportsTown.php new file mode 100644 index 0000000..1e422c1 --- /dev/null +++ b/Tests/Functional/Assertions/Import/ImportsTown.php @@ -0,0 +1,24 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'remote_id' => 'https://thuecat.org/resources/043064193523-jcyt', + 'title' => 'Erfurt', + 'description' => 'Krämerbrücke, Dom, Alte Synagoge – die Thüringer Landeshauptstadt Erfurt hat viele Kulturschätze. Und ein wunderbar junges, studentisches Flair.Eine gute Mischung für alle, die beim Schlendern und Bummeln gerne Städte entdecken: Denn in Erfurt findet man einen wunderbaren mittelalterlichen Stadtkern – mit vielen netten Läden, Cafès und Restaurants. Urlauber wie Einheimische bummeln durch die Gassen der Altstadt, aus allen Ecken wispern Geschichte und alte Geschichten. Stolze historische Bügerhäuser bilden eine der schönsten Altstädte Europas, mittendrin das neugotische Rathaus aus den 1870er-Jahren am Fischmarkt, die spitztürmige St. Severikirche und der mächtige Dom, 1117 erstmals urkundlich erwähnt – auf seiner schier endlosen, kaskadenförmigen Freitreppe chillen Jung und Alt gern in der Abendsonne. Ehe sie weiter ziehen zum Tagesausklang in eine der coolen Kneipen und Bars (Tipp: Oma Lilo oder Cafè Hilgenfeld), in die Wein-Destille am benachbarten Petersberg oder in eins der lässigen Restaurants (Tipp: Mathilda oder Ballenberger), wo zum freundlichen Miteinander eine frische und moderne Küche serviert wird.In Erfurt pulsiert das Leben, lassen Sie sich einfach treiben. Von Ihrer Neugierde ...', + 'managed_by' => '1', + ], + ], + 'tx_thuecat_organisation' => [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'remote_id' => 'https://thuecat.org/resources/018132452787-ngbe', + 'title' => 'Erfurt Tourismus und Marketing GmbH', + ], + ], +]; diff --git a/Tests/Functional/Assertions/Import/ImportsTownWithRelation.php b/Tests/Functional/Assertions/Import/ImportsTownWithRelation.php new file mode 100644 index 0000000..1e422c1 --- /dev/null +++ b/Tests/Functional/Assertions/Import/ImportsTownWithRelation.php @@ -0,0 +1,24 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'remote_id' => 'https://thuecat.org/resources/043064193523-jcyt', + 'title' => 'Erfurt', + 'description' => 'Krämerbrücke, Dom, Alte Synagoge – die Thüringer Landeshauptstadt Erfurt hat viele Kulturschätze. Und ein wunderbar junges, studentisches Flair.Eine gute Mischung für alle, die beim Schlendern und Bummeln gerne Städte entdecken: Denn in Erfurt findet man einen wunderbaren mittelalterlichen Stadtkern – mit vielen netten Läden, Cafès und Restaurants. Urlauber wie Einheimische bummeln durch die Gassen der Altstadt, aus allen Ecken wispern Geschichte und alte Geschichten. Stolze historische Bügerhäuser bilden eine der schönsten Altstädte Europas, mittendrin das neugotische Rathaus aus den 1870er-Jahren am Fischmarkt, die spitztürmige St. Severikirche und der mächtige Dom, 1117 erstmals urkundlich erwähnt – auf seiner schier endlosen, kaskadenförmigen Freitreppe chillen Jung und Alt gern in der Abendsonne. Ehe sie weiter ziehen zum Tagesausklang in eine der coolen Kneipen und Bars (Tipp: Oma Lilo oder Cafè Hilgenfeld), in die Wein-Destille am benachbarten Petersberg oder in eins der lässigen Restaurants (Tipp: Mathilda oder Ballenberger), wo zum freundlichen Miteinander eine frische und moderne Küche serviert wird.In Erfurt pulsiert das Leben, lassen Sie sich einfach treiben. Von Ihrer Neugierde ...', + 'managed_by' => '1', + ], + ], + 'tx_thuecat_organisation' => [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'remote_id' => 'https://thuecat.org/resources/018132452787-ngbe', + 'title' => 'Erfurt Tourismus und Marketing GmbH', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Frontend/Content.php b/Tests/Functional/Fixtures/Frontend/Content.php new file mode 100644 index 0000000..719137f --- /dev/null +++ b/Tests/Functional/Fixtures/Frontend/Content.php @@ -0,0 +1,96 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'title' => 'Root', + 'doktype' => PageRepository::DOKTYPE_DEFAULT, + 'slug' => '/', + 'sorting' => '128', + 'deleted' => '0', + ], + 1 => [ + 'uid' => '2', + 'pid' => '1', + 'title' => 'Tourist Attraction', + 'doktype' => PageRepository::DOKTYPE_DEFAULT, + 'slug' => '/example-attraction/', + 'sorting' => '128', + 'deleted' => '0', + ], + 2 => [ + 'uid' => '3', + 'pid' => '1', + 'title' => 'Storage', + 'doktype' => PageRepository::DOKTYPE_SYSFOLDER, + 'sorting' => '128', + 'deleted' => '0', + ], + 3 => [ + 'uid' => '4', + 'pid' => '1', + 'title' => 'Tourist Attraction false', + 'slug' => '/example-attraction-false/', + 'sorting' => '128', + 'deleted' => '0', + ], + 4 => [ + 'uid' => '5', + 'pid' => '1', + 'title' => 'Tourist Attraction true', + 'slug' => '/example-attraction-true/', + 'sorting' => '128', + 'deleted' => '0', + ], + ], + 'tt_content' => [ + 0 => [ + 'uid' => '2', + 'pid' => '2', + 'hidden' => '0', + 'sorting' => '1', + 'CType' => 'thuecat_tourist_attraction', + 'header' => 'Show Example Tourist Attraction', + 'deleted' => '0', + 'starttime' => '0', + 'endtime' => '0', + 'colPos' => '0', + 'sys_language_uid' => '0', + 'records' => '1', + ], + 1 => [ + 'uid' => '3', + 'pid' => '4', + 'hidden' => '0', + 'sorting' => '1', + 'CType' => 'thuecat_tourist_attraction', + 'header' => 'Show Example Tourist Attraction with false', + 'deleted' => '0', + 'starttime' => '0', + 'endtime' => '0', + 'colPos' => '0', + 'sys_language_uid' => '0', + 'records' => '2', + ], + 2 => [ + 'uid' => '4', + 'pid' => '5', + 'hidden' => '0', + 'sorting' => '1', + 'CType' => 'thuecat_tourist_attraction', + 'header' => 'Show Example Tourist Attraction with true', + 'deleted' => '0', + 'starttime' => '0', + 'endtime' => '0', + 'colPos' => '0', + 'sys_language_uid' => '0', + 'records' => '3', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Frontend/Content.xml b/Tests/Functional/Fixtures/Frontend/Content.xml deleted file mode 100644 index e04ae05..0000000 --- a/Tests/Functional/Fixtures/Frontend/Content.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - - 1 - 0 - Root - / - 128 - 0 - - - 2 - 1 - Tourist Attraction - /example-attraction/ - 128 - 0 - - - 3 - 1 - Storage - 254 - 128 - 0 - - - 4 - 1 - Tourist Attraction false - /example-attraction-false/ - 128 - 0 - - - 5 - 1 - Tourist Attraction true - /example-attraction-true/ - 128 - 0 - - - 2 - 2 - 0 - 1 - thuecat_tourist_attraction -
Show Example Tourist Attraction
- 0 - 0 - 0 - 0 - 0 - 1 -
- - 3 - 4 - 0 - 1 - thuecat_tourist_attraction -
Show Example Tourist Attraction with false
- 0 - 0 - 0 - 0 - 0 - 2 -
- - 4 - 5 - 0 - 1 - thuecat_tourist_attraction -
Show Example Tourist Attraction with true
- 0 - 0 - 0 - 0 - 0 - 3 -
-
- diff --git a/Tests/Functional/Fixtures/Frontend/SecondTouristAttraction.php b/Tests/Functional/Fixtures/Frontend/SecondTouristAttraction.php new file mode 100644 index 0000000..9b4dedb --- /dev/null +++ b/Tests/Functional/Fixtures/Frontend/SecondTouristAttraction.php @@ -0,0 +1,35 @@ + [ + 0 => [ + 'uid' => '2', + 'pid' => '3', + 'title' => 'Eine weitere Attraktion', + 'description' => 'Die Beschreibung der Attraktion', + 'town' => '1', + 'media' => '[{"mainImage":true,"type":"image","title":"Erfurt-Dom und Severikirche-beleuchtet.jpg","description":"","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5159216\\/Preview-1280x0\\/image","copyrightYear":2016,"author":"Image Author","license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":""}},{"mainImage":false,"type":"image","title":"Erfurt-Dom-und-Severikirche.jpg","description":"Sicht auf Dom St. Marien, St. Severikirche sowie die davor liegenden Klostergeb\\u00e4ude und einem Ausschnitt des Biergartens umgeben von einem d\\u00e4mmerungsverf\\u00e4rten Himmel","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5159186\\/Preview-1280x0\\/image","copyrightYear":2020,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":""}},{"mainImage":false,"type":"image","title":"Erfurt-Dom und Severikirche-beleuchtet.jpg","description":"","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5159216\\/Preview-1280x0\\/image","copyrightYear":2016,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":""}}]', + 'opening_hours' => '[{"opens":"09:30:00","closes":"18:00:00","from":{"date":"2021-05-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2021-10-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Saturday","Friday","Thursday","Tuesday","Monday","Wednesday"]},{"opens":"13:00:00","closes":"18:00:00","from":{"date":"2021-05-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2021-10-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Sunday"]},{"opens":"09:30:00","closes":"17:00:00","from":{"date":"2021-11-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2022-04-30 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Saturday","Friday","Thursday","Tuesday","Monday","Wednesday"]},{"opens":"13:00:00","closes":"17:00:00","from":{"date":"2021-11-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2022-04-30 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Sunday","PublicHolidays"]}]', + 'address' => '{"street":"Beispielstraße 1a","zip":"99084","city":"Beispielstadt","email":"example@example.com","phone":"(0)30 23125 000","fax":"","geo":{"latitude":50.975955358589545,"longitude":11.023667024961856}}', + 'url' => 'https://example.com/attraction', + 'offers' => '[{"type":"GuidedTourOffer","title":"F\\u00fchrungen","description":"Immer samstags, um 11:15 Uhr findet eine \\u00f6ffentliche F\\u00fchrung durch das Museum statt. Dauer etwa 90 Minuten","prices":[{"title":"Erwachsene","description":"","price":8,"currency":"EUR","rule":"PerPerson"},{"title":"Erm\\u00e4\\u00dfigt","description":"als erm\\u00e4\\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt","price":5,"currency":"EUR","rule":"PerPerson"}]},{"type":"EntryOffer","title":"Eintritt","description":"Schulklassen und Kitagruppen im Rahmen des Unterrichts: Eintritt frei\\nAn jedem ersten Dienstag im Monat: Eintritt frei","prices":[{"title":"Erm\\u00e4\\u00dfigt","description":"als erm\\u00e4\\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt","price":5,"currency":"EUR","rule":"PerPerson"},{"title":"Familienkarte","description":"","price":17,"currency":"EUR","rule":"PerGroup"},{"title":"ErfurtCard","description":"","price":14.9,"currency":"EUR","rule":"PerPackage"},{"title":"Erwachsene","description":"","price":8,"currency":"EUR","rule":"PerPerson"}]}]', + 'slogan' => 'Highlight', + 'start_of_construction' => '11. Jh', + 'sanitation' => 'Toilets,DisabledToilets,NappyChangingArea,FamilyAndChildFriendly', + 'other_service' => 'Playground,SeatingPossibilitiesRestArea,SouvenirShop,PlayCornerOrPlayArea', + 'museum_service' => 'MuseumShop,PedagogicalOffer,ZeroInformationMuseumService', + 'architectural_style' => 'ArchitectureOfHomelandSecurity,ArtDeco,ArtNouveau,Baroque,BauhausStyle,Brutalism,Classicism,Constructivism,CriticalRegionalism,Deconstructivism,Expressionism,Functionalism,GothicArt,GothicRevival,HighTechArchitecture,Historicism,InternationalStyle,Minimalism,Modernism,Neoclassicism,Neorenaissance,NewBuilding,NewObjectivity,OrganicConstruction,PostWarModernism,PostmodernAge,Rationalism,Renaissance,Rococo,RomanesquePeriod,ZeroInformationArchitecturalStyle', + 'traffic_infrastructure' => 'BicycleLockersEnumMem,BicycleStandsEnumMem,BicycleStandsBicycleLockersEnumMem,BusParkCoachParkEnumMem,EbikeChargingStationEnumMem,ElectricVehicleCarChargingStationEnumMem,ZeroSpecialTrafficInfrastructure', + 'payment_accepted' => 'AliPay,AmericanExpress,ApplePay,CashPayment,EC,InstantBankTransfer,Invoice,MasterCard,PayPal,Visa', + 'digital_offer' => 'AppForMobileDevices,AudioGuide,AugmentedReality,VideoGuide,VirtuellReality,ZeroDigitalOffer', + 'photography' => 'PhotoLicenceFeeRequired,TakingPicturesPermitted,ZeroPhotography,some free text value for photography', + 'pets_allowed' => 'Tiere sind im Gebäude nicht gestattet, ausgenommen sind Blinden- und Blindenbegleithunde.', + 'available_languages' => 'German,English,French', + 'distance_to_public_transport' => '250:MTR', + 'parking_facility_near_by' => '1,2', + 'accessibility_specification' => '{"accessibilityCertificationStatus":"AccessibilityChecked","accessibilitySearchCriteria":{"facilityAccessibilityDeaf":["AudioInductionLoop","FlashingSignalCallWaitingDoor","SpecialOffersDeafPeople","SpecialOffersHearingImpairment","VisualConfirmationDistressCallElevator"],"facilityAccessibilityMental":["ColoredOrPictorialGuidanceSystem","InformationInEasyLanguage","InformationWithPictogramsOrPictures"],"facilityAccessibilityVisual":["AssistanceDogsWelcome","GuidanceSystemWithFloorIndicators","InformationBrailleOrPrismaticFont","OffersInPictoralLanguage","SpecialOffersBlindPeople","SpecialOffersVisualImpairment","TactileOffers","VisuallyContrastingStepEdges"],"facilityAccessibilityWalking":["AllRoomsStepFreeAccess","EightyCMWidthPassageWays","EntryAidSwimmingPool","GrabRailInShower","HandrailsOnBothSidesOfAllStaircases","HingedGrabRailToilet","LateralAccessibleToilet","MinumumManoeuvringSpaceShower","NinetyCMWidthPassageWays","NursingBed","ParkingPeopleWithDisabilities","SeventyCMWidthPassageWays","ShowerSeat","SpecialOffersWalkingImpairment","SpecialOffersWheelchairUsers","StepFreeAccess","StepFreeShower","ToiletsPeopleWithDisabilities"]},"certificationAccessibilityDeaf":"Full","certificationAccessibilityMental":"None","certificationAccessibilityPartiallyDeaf":"None","certificationAccessibilityPartiallyVisual":"Info","certificationAccessibilityVisual":"None","certificationAccessibilityWalking":"Info","certificationAccessibilityWheelchair":"Info","shortDescriptionAccessibilityAllGenerations":"Deutsche Beschreibung von shortDescriptionAccessibilityAllGenerations","shortDescriptionAccessibilityAllergic":"Deutsche Beschreibung von shortDescriptionAccessibilityAllergic","shortDescriptionAccessibilityDeaf":"Deutsche Beschreibung von shortDescriptionAccessibilityDeaf","shortDescriptionAccessibilityMental":"Deutsche Beschreibung von shortDescriptionAccessibilityMental","shortDescriptionAccessibilityVisual":"Deutsche Beschreibung von shortDescriptionAccessibilityVisual","shortDescriptionAccessibilityWalking":"Deutsche Beschreibung von shortDescriptionAccessibilityWalking"}', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Frontend/SecondTouristAttraction.xml b/Tests/Functional/Fixtures/Frontend/SecondTouristAttraction.xml deleted file mode 100644 index 8ec52b8..0000000 --- a/Tests/Functional/Fixtures/Frontend/SecondTouristAttraction.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - 2 - 3 - Eine weitere Attraktion - Die Beschreibung der Attraktion - 1 - [{"mainImage":true,"type":"image","title":"Erfurt-Dom und Severikirche-beleuchtet.jpg","description":"","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159216\/Preview-1280x0\/image","copyrightYear":2016,"author":"Image Author","license":{"type":"https:\/\/creativecommons.org\/licenses\/by\/4.0\/","author":""}},{"mainImage":false,"type":"image","title":"Erfurt-Dom-und-Severikirche.jpg","description":"Sicht auf Dom St. Marien, St. Severikirche sowie die davor liegenden Klostergeb\u00e4ude und einem Ausschnitt des Biergartens umgeben von einem d\u00e4mmerungsverf\u00e4rten Himmel","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159186\/Preview-1280x0\/image","copyrightYear":2020,"license":{"type":"https:\/\/creativecommons.org\/licenses\/by\/4.0\/","author":""}},{"mainImage":false,"type":"image","title":"Erfurt-Dom und Severikirche-beleuchtet.jpg","description":"","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159216\/Preview-1280x0\/image","copyrightYear":2016,"license":{"type":"https:\/\/creativecommons.org\/licenses\/by\/4.0\/","author":""}}] - [{"opens":"09:30:00","closes":"18:00:00","from":{"date":"2021-05-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2021-10-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Saturday","Friday","Thursday","Tuesday","Monday","Wednesday"]},{"opens":"13:00:00","closes":"18:00:00","from":{"date":"2021-05-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2021-10-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Sunday"]},{"opens":"09:30:00","closes":"17:00:00","from":{"date":"2021-11-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2022-04-30 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Saturday","Friday","Thursday","Tuesday","Monday","Wednesday"]},{"opens":"13:00:00","closes":"17:00:00","from":{"date":"2021-11-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2022-04-30 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Sunday","PublicHolidays"]}] -
{"street":"Beispielstraße 1a","zip":"99084","city":"Beispielstadt","email":"example@example.com","phone":"(0)30 23125 000","fax":"","geo":{"latitude":50.975955358589545,"longitude":11.023667024961856}}
- https://example.com/attraction - [{"type":"GuidedTourOffer","title":"F\u00fchrungen","description":"Immer samstags, um 11:15 Uhr findet eine \u00f6ffentliche F\u00fchrung durch das Museum statt. Dauer etwa 90 Minuten","prices":[{"title":"Erwachsene","description":"","price":8,"currency":"EUR","rule":"PerPerson"},{"title":"Erm\u00e4\u00dfigt","description":"als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt","price":5,"currency":"EUR","rule":"PerPerson"}]},{"type":"EntryOffer","title":"Eintritt","description":"Schulklassen und Kitagruppen im Rahmen des Unterrichts: Eintritt frei\nAn jedem ersten Dienstag im Monat: Eintritt frei","prices":[{"title":"Erm\u00e4\u00dfigt","description":"als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt","price":5,"currency":"EUR","rule":"PerPerson"},{"title":"Familienkarte","description":"","price":17,"currency":"EUR","rule":"PerGroup"},{"title":"ErfurtCard","description":"","price":14.9,"currency":"EUR","rule":"PerPackage"},{"title":"Erwachsene","description":"","price":8,"currency":"EUR","rule":"PerPerson"}]}] - Highlight - 11. Jh - Toilets,DisabledToilets,NappyChangingArea,FamilyAndChildFriendly - Playground,SeatingPossibilitiesRestArea,SouvenirShop,PlayCornerOrPlayArea - MuseumShop,PedagogicalOffer,ZeroInformationMuseumService - ArchitectureOfHomelandSecurity,ArtDeco,ArtNouveau,Baroque,BauhausStyle,Brutalism,Classicism,Constructivism,CriticalRegionalism,Deconstructivism,Expressionism,Functionalism,GothicArt,GothicRevival,HighTechArchitecture,Historicism,InternationalStyle,Minimalism,Modernism,Neoclassicism,Neorenaissance,NewBuilding,NewObjectivity,OrganicConstruction,PostWarModernism,PostmodernAge,Rationalism,Renaissance,Rococo,RomanesquePeriod,ZeroInformationArchitecturalStyle - BicycleLockersEnumMem,BicycleStandsEnumMem,BicycleStandsBicycleLockersEnumMem,BusParkCoachParkEnumMem,EbikeChargingStationEnumMem,ElectricVehicleCarChargingStationEnumMem,ZeroSpecialTrafficInfrastructure - AliPay,AmericanExpress,ApplePay,CashPayment,EC,InstantBankTransfer,Invoice,MasterCard,PayPal,Visa - AppForMobileDevices,AudioGuide,AugmentedReality,VideoGuide,VirtuellReality,ZeroDigitalOffer - PhotoLicenceFeeRequired,TakingPicturesPermitted,ZeroPhotography,some free text value for photography - Tiere sind im Gebäude nicht gestattet, ausgenommen sind Blinden- und Blindenbegleithunde. - German,English,French - 250:MTR - 1,2 - {"accessibilityCertificationStatus":"AccessibilityChecked","accessibilitySearchCriteria":{"facilityAccessibilityDeaf":["AudioInductionLoop","FlashingSignalCallWaitingDoor","SpecialOffersDeafPeople","SpecialOffersHearingImpairment","VisualConfirmationDistressCallElevator"],"facilityAccessibilityMental":["ColoredOrPictorialGuidanceSystem","InformationInEasyLanguage","InformationWithPictogramsOrPictures"],"facilityAccessibilityVisual":["AssistanceDogsWelcome","GuidanceSystemWithFloorIndicators","InformationBrailleOrPrismaticFont","OffersInPictoralLanguage","SpecialOffersBlindPeople","SpecialOffersVisualImpairment","TactileOffers","VisuallyContrastingStepEdges"],"facilityAccessibilityWalking":["AllRoomsStepFreeAccess","EightyCMWidthPassageWays","EntryAidSwimmingPool","GrabRailInShower","HandrailsOnBothSidesOfAllStaircases","HingedGrabRailToilet","LateralAccessibleToilet","MinumumManoeuvringSpaceShower","NinetyCMWidthPassageWays","NursingBed","ParkingPeopleWithDisabilities","SeventyCMWidthPassageWays","ShowerSeat","SpecialOffersWalkingImpairment","SpecialOffersWheelchairUsers","StepFreeAccess","StepFreeShower","ToiletsPeopleWithDisabilities"]},"certificationAccessibilityDeaf":"Full","certificationAccessibilityMental":"None","certificationAccessibilityPartiallyDeaf":"None","certificationAccessibilityPartiallyVisual":"Info","certificationAccessibilityVisual":"None","certificationAccessibilityWalking":"Info","certificationAccessibilityWheelchair":"Info","shortDescriptionAccessibilityAllGenerations":"Deutsche Beschreibung von shortDescriptionAccessibilityAllGenerations","shortDescriptionAccessibilityAllergic":"Deutsche Beschreibung von shortDescriptionAccessibilityAllergic","shortDescriptionAccessibilityDeaf":"Deutsche Beschreibung von shortDescriptionAccessibilityDeaf","shortDescriptionAccessibilityMental":"Deutsche Beschreibung von shortDescriptionAccessibilityMental","shortDescriptionAccessibilityVisual":"Deutsche Beschreibung von shortDescriptionAccessibilityVisual","shortDescriptionAccessibilityWalking":"Deutsche Beschreibung von shortDescriptionAccessibilityWalking"} -
-
- diff --git a/Tests/Functional/Fixtures/Frontend/TouristAttractionWithEditorialImages.php b/Tests/Functional/Fixtures/Frontend/TouristAttractionWithEditorialImages.php new file mode 100644 index 0000000..4e3bb12 --- /dev/null +++ b/Tests/Functional/Fixtures/Frontend/TouristAttractionWithEditorialImages.php @@ -0,0 +1,60 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '3', + 'title' => 'Attraktion mit redaktionellen Bildern', + 'editorial_images' => '2', + ], + ], + 'sys_file_reference' => [ + 0 => [ + 'uid' => '1', + 'uid_local' => '1', + 'uid_foreign' => '1', + 'tablenames' => 'tx_thuecat_tourist_attraction', + 'fieldname' => 'editorial_images', + 'sorting_foreign' => '1', + ], + 1 => [ + 'uid' => '2', + 'uid_local' => '2', + 'uid_foreign' => '1', + 'tablenames' => 'tx_thuecat_tourist_attraction', + 'fieldname' => 'editorial_images', + 'sorting_foreign' => '2', + ], + ], + 'sys_file' => [ + 0 => [ + 'uid' => '1', + 'type' => '2', + 'storage' => '1', + 'identifier' => '/tourismus/images/inhalte/sehenswertes/parks_gaerten/hirschgarten/2998_Spielplaetze_Hirschgarten.jpg', + 'extension' => 'jpg', + 'mime_type' => 'image/jpeg', + 'name' => '2998_Spielplaetze_Hirschgarten.jpg', + 'sha1' => '61079cbeb5d13c21d20dbbcc2e28e9c8fa04b3b4', + 'size' => '7329219', + 'identifier_hash' => '69066cc9c3b5ff135a7daa36059b18c75b3d9a23', + 'folder_hash' => '4dd66a1c0a2a0ab89a22bfe734df75d9750d28f2', + ], + 1 => [ + 'uid' => '2', + 'type' => '2', + 'storage' => '1', + 'identifier' => '/tourismus/images/inhalte/sehenswertes/sehenswuerdigkeiten/Petersberg/20_Erfurt-Schriftzug_Petersberg_2021__c_Stadtverwaltung_Erfurt_CC-BY-NC-SA.JPG', + 'extension' => 'JPG', + 'mime_type' => 'image/jpeg', + 'name' => '20_Erfurt-Schriftzug_Petersberg_2021__c_Stadtverwaltung_Erfurt_CC-BY-NC-SA.JPG', + 'sha1' => 'f4c45d3c738d29162759ecd7d2dbc9af2a8f515f', + 'size' => '2807135', + 'identifier_hash' => '384f006a1452e901badb0db799fa7ff364e88a5e', + 'folder_hash' => '01086eae3464ef516edc0756ba3e12e35e09c33d', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Frontend/TouristAttractionWithEditorialImages.xml b/Tests/Functional/Fixtures/Frontend/TouristAttractionWithEditorialImages.xml deleted file mode 100644 index d7de1d0..0000000 --- a/Tests/Functional/Fixtures/Frontend/TouristAttractionWithEditorialImages.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - 1 - 3 - Attraktion mit redaktionellen Bildern - 2 - - - - 1 - 1 - 1 - tx_thuecat_tourist_attraction - editorial_images - 1 - sys_file - - - - 2 - 2 - 1 - tx_thuecat_tourist_attraction - editorial_images - 2 - sys_file - - - - 1 - 2 - 1 - /tourismus/images/inhalte/sehenswertes/parks_gaerten/hirschgarten/2998_Spielplaetze_Hirschgarten.jpg - jpg - image/jpeg - 2998_Spielplaetze_Hirschgarten.jpg - 61079cbeb5d13c21d20dbbcc2e28e9c8fa04b3b4 - 7329219 - 69066cc9c3b5ff135a7daa36059b18c75b3d9a23 - 4dd66a1c0a2a0ab89a22bfe734df75d9750d28f2 - - - - 2 - 2 - 1 - /tourismus/images/inhalte/sehenswertes/sehenswuerdigkeiten/Petersberg/20_Erfurt-Schriftzug_Petersberg_2021__c_Stadtverwaltung_Erfurt_CC-BY-NC-SA.JPG - JPG - image/jpeg - 20_Erfurt-Schriftzug_Petersberg_2021__c_Stadtverwaltung_Erfurt_CC-BY-NC-SA.JPG - f4c45d3c738d29162759ecd7d2dbc9af2a8f515f - 2807135 - 384f006a1452e901badb0db799fa7ff364e88a5e - 01086eae3464ef516edc0756ba3e12e35e09c33d - - - diff --git a/Tests/Functional/Fixtures/Frontend/TouristAttractionWithOfferTypes.php b/Tests/Functional/Fixtures/Frontend/TouristAttractionWithOfferTypes.php new file mode 100644 index 0000000..6800373 --- /dev/null +++ b/Tests/Functional/Fixtures/Frontend/TouristAttractionWithOfferTypes.php @@ -0,0 +1,14 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '3', + 'title' => 'Attraktion mit Angebotstypen', + 'offers' => '[{"description":"","prices":[{"currency":"EUR","description":"","price":8,"rule":"PerGroup","title":"Schulklassen"}],"title":"Führungen","type":"GuidedTourOffer"},{"description":"","prices":[{"currency":"EUR","description":"","price":8,"rule":"PerGroup","title":"Schulklassen"}],"title":"Verkostung","type":"Tasting"},{"description":"","prices":[{"currency":"EUR","description":"","price":8,"rule":"PerGroup","title":"Schulklassen"}],"title":"Eintritt 1","type":"EntryOffer"},{"description":"","prices":[{"currency":"EUR","description":"","price":8,"rule":"PerGroup","title":"Schulklassen"}],"title":"Eintritt 2","type":"EntryOffer"},{"description":"","prices":[{"currency":"EUR","description":"","price":8,"rule":"PerGroup","title":"Schulklassen"}],"title":"Parkgebühr","type":"ParkingFee"}]', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Frontend/TouristAttractionWithOfferTypes.xml b/Tests/Functional/Fixtures/Frontend/TouristAttractionWithOfferTypes.xml deleted file mode 100644 index 26422a2..0000000 --- a/Tests/Functional/Fixtures/Frontend/TouristAttractionWithOfferTypes.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - 1 - 3 - Attraktion mit Angebotstypen - [{"description":"","prices":[{"currency":"EUR","description":"","price":8,"rule":"PerGroup","title":"Schulklassen"}],"title":"Führungen","type":"GuidedTourOffer"},{"description":"","prices":[{"currency":"EUR","description":"","price":8,"rule":"PerGroup","title":"Schulklassen"}],"title":"Verkostung","type":"Tasting"},{"description":"","prices":[{"currency":"EUR","description":"","price":8,"rule":"PerGroup","title":"Schulklassen"}],"title":"Eintritt 1","type":"EntryOffer"},{"description":"","prices":[{"currency":"EUR","description":"","price":8,"rule":"PerGroup","title":"Schulklassen"}],"title":"Eintritt 2","type":"EntryOffer"},{"description":"","prices":[{"currency":"EUR","description":"","price":8,"rule":"PerGroup","title":"Schulklassen"}],"title":"Parkgebühr","type":"ParkingFee"}] - - - diff --git a/Tests/Functional/Fixtures/Frontend/TouristAttractionWithPrices.php b/Tests/Functional/Fixtures/Frontend/TouristAttractionWithPrices.php new file mode 100644 index 0000000..0019477 --- /dev/null +++ b/Tests/Functional/Fixtures/Frontend/TouristAttractionWithPrices.php @@ -0,0 +1,14 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '3', + 'title' => 'Attraktion mit Preisen', + 'offers' => '[{"prices":[{"currency":"EUR","description":"","price":8,"rule":"PerGroup","title":"Schulklassen"},{"currency":"EUR","description":"","price":8,"rule":"PerPerson","title":"Erwachsene"},{"currency":"EUR","description":"","price":5,"rule":"PerPerson","title":"Familienkarte B"},{"currency":"EUR","description":"","price":5,"rule":"PerPerson","title":"Familienkarte A"}],"description":"","title":"Führungen","type":"GuidedTourOffer"}]', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Frontend/TouristAttractionWithPrices.xml b/Tests/Functional/Fixtures/Frontend/TouristAttractionWithPrices.xml deleted file mode 100644 index 964911c..0000000 --- a/Tests/Functional/Fixtures/Frontend/TouristAttractionWithPrices.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - 1 - 3 - Attraktion mit Preisen - [{"prices":[{"currency":"EUR","description":"","price":8,"rule":"PerGroup","title":"Schulklassen"},{"currency":"EUR","description":"","price":8,"rule":"PerPerson","title":"Erwachsene"},{"currency":"EUR","description":"","price":5,"rule":"PerPerson","title":"Familienkarte B"},{"currency":"EUR","description":"","price":5,"rule":"PerPerson","title":"Familienkarte A"}],"description":"","title":"Führungen","type":"GuidedTourOffer"}] - - - diff --git a/Tests/Functional/Fixtures/Frontend/TouristAttractions.php b/Tests/Functional/Fixtures/Frontend/TouristAttractions.php new file mode 100644 index 0000000..586d425 --- /dev/null +++ b/Tests/Functional/Fixtures/Frontend/TouristAttractions.php @@ -0,0 +1,57 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '3', + 'title' => 'Erste Attraktion', + 'description' => 'Die Beschreibung der Attraktion', + 'town' => '1', + 'media' => '[{"mainImage":true,"type":"image","title":"Erfurt-Dom und Severikirche-beleuchtet.jpg","description":"","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5159216\\/Preview-1280x0\\/image","copyrightYear":2016,"author":"Image Author","license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":""}},{"mainImage":false,"type":"image","title":"Erfurt-Dom-und-Severikirche.jpg","description":"Sicht auf Dom St. Marien, St. Severikirche sowie die davor liegenden Klostergeb\\u00e4ude und einem Ausschnitt des Biergartens umgeben von einem d\\u00e4mmerungsverf\\u00e4rten Himmel","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5159186\\/Preview-1280x0\\/image","copyrightYear":2020,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":""}},{"mainImage":false,"type":"image","title":"Erfurt-Dom und Severikirche-beleuchtet.jpg","description":"","url":"https:\\/\\/cms.thuecat.org\\/o\\/adaptive-media\\/image\\/5159216\\/Preview-1280x0\\/image","copyrightYear":2016,"license":{"type":"https:\\/\\/creativecommons.org\\/licenses\\/by\\/4.0\\/","author":""}}]', + 'opening_hours' => '[{"opens":"09:30:00","closes":"18:00:00","from":{"date":"2021-05-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2021-10-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Saturday","Friday","Thursday","Tuesday","Monday","Wednesday"]},{"opens":"13:00:00","closes":"18:00:00","from":{"date":"2021-05-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2021-10-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Sunday"]},{"opens":"09:30:00","closes":"17:00:00","from":{"date":"2021-11-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2022-04-30 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Saturday","Friday","Thursday","Tuesday","Monday","Wednesday"]},{"opens":"13:00:00","closes":"17:00:00","from":{"date":"2021-11-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2022-04-30 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Sunday","PublicHolidays"]}]', + 'address' => '{"street":"Beispielstraße 1a","zip":"99084","city":"Beispielstadt","email":"example@example.com","phone":"(0)30 23125 000","fax":"","geo":{"latitude":50.975955358589545,"longitude":11.023667024961856}}', + 'url' => 'https://example.com/attraction', + 'offers' => '[{"type":"GuidedTourOffer","title":"F\\u00fchrungen","description":"Immer samstags, um 11:15 Uhr findet eine \\u00f6ffentliche F\\u00fchrung durch das Museum statt. Dauer etwa 90 Minuten","prices":[{"title":"Erwachsene","description":"","price":8,"currency":"EUR","rule":"PerPerson"},{"title":"Erm\\u00e4\\u00dfigt","description":"als erm\\u00e4\\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt","price":5,"currency":"EUR","rule":"PerPerson"}]},{"type":"EntryOffer","title":"Eintritt","description":"Schulklassen und Kitagruppen im Rahmen des Unterrichts: Eintritt frei\\nAn jedem ersten Dienstag im Monat: Eintritt frei","prices":[{"title":"Erm\\u00e4\\u00dfigt","description":"als erm\\u00e4\\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt","price":5,"currency":"EUR","rule":"PerPerson"},{"title":"Familienkarte","description":"","price":17,"currency":"EUR","rule":"PerGroup"},{"title":"ErfurtCard","description":"","price":14.9,"currency":"EUR","rule":"PerPackage"},{"title":"Erwachsene","description":"","price":8,"currency":"EUR","rule":"PerPerson"}]}]', + 'slogan' => 'Highlight', + 'start_of_construction' => '11. Jh', + 'sanitation' => 'Toilets,DisabledToilets,NappyChangingArea,FamilyAndChildFriendly', + 'other_service' => 'Playground,SeatingPossibilitiesRestArea,SouvenirShop,PlayCornerOrPlayArea', + 'museum_service' => 'MuseumShop,PedagogicalOffer,ZeroInformationMuseumService', + 'architectural_style' => 'ArchitectureOfHomelandSecurity,ArtDeco,ArtNouveau,Baroque,BauhausStyle,Brutalism,Classicism,Constructivism,CriticalRegionalism,Deconstructivism,Expressionism,Functionalism,GothicArt,GothicRevival,HighTechArchitecture,Historicism,InternationalStyle,Minimalism,Modernism,Neoclassicism,Neorenaissance,NewBuilding,NewObjectivity,OrganicConstruction,PostWarModernism,PostmodernAge,Rationalism,Renaissance,Rococo,RomanesquePeriod,ZeroInformationArchitecturalStyle', + 'traffic_infrastructure' => 'BicycleLockersEnumMem,BicycleStandsEnumMem,BicycleStandsBicycleLockersEnumMem,BusParkCoachParkEnumMem,EbikeChargingStationEnumMem,ElectricVehicleCarChargingStationEnumMem,ZeroSpecialTrafficInfrastructure', + 'payment_accepted' => 'AliPay,AmericanExpress,ApplePay,CashPayment,EC,InstantBankTransfer,Invoice,MasterCard,PayPal,Visa', + 'digital_offer' => 'AppForMobileDevices,AudioGuide,AugmentedReality,VideoGuide,VirtuellReality,ZeroDigitalOffer', + 'photography' => 'PhotoLicenceFeeRequired,TakingPicturesPermitted,ZeroPhotography,some free text value for photography', + 'pets_allowed' => 'Tiere sind im Gebäude nicht gestattet, ausgenommen sind Blinden- und Blindenbegleithunde.', + 'available_languages' => 'German,English,French', + 'distance_to_public_transport' => '250:MTR', + 'parking_facility_near_by' => '1,2', + 'accessibility_specification' => '{"accessibilityCertificationStatus":"AccessibilityChecked","accessibilitySearchCriteria":{"facilityAccessibilityDeaf":["AudioInductionLoop","FlashingSignalCallWaitingDoor","SpecialOffersDeafPeople","SpecialOffersHearingImpairment","VisualConfirmationDistressCallElevator"],"facilityAccessibilityMental":["ColoredOrPictorialGuidanceSystem","InformationInEasyLanguage","InformationWithPictogramsOrPictures"],"facilityAccessibilityVisual":["AssistanceDogsWelcome","GuidanceSystemWithFloorIndicators","InformationBrailleOrPrismaticFont","OffersInPictoralLanguage","SpecialOffersBlindPeople","SpecialOffersVisualImpairment","TactileOffers","VisuallyContrastingStepEdges"],"facilityAccessibilityWalking":["AllRoomsStepFreeAccess","EightyCMWidthPassageWays","EntryAidSwimmingPool","GrabRailInShower","HandrailsOnBothSidesOfAllStaircases","HingedGrabRailToilet","LateralAccessibleToilet","MinumumManoeuvringSpaceShower","NinetyCMWidthPassageWays","NursingBed","ParkingPeopleWithDisabilities","SeventyCMWidthPassageWays","ShowerSeat","SpecialOffersWalkingImpairment","SpecialOffersWheelchairUsers","StepFreeAccess","StepFreeShower","ToiletsPeopleWithDisabilities"]},"certificationAccessibilityDeaf":"Full","certificationAccessibilityMental":"None","certificationAccessibilityPartiallyDeaf":"None","certificationAccessibilityPartiallyVisual":"Info","certificationAccessibilityVisual":"None","certificationAccessibilityWalking":"Info","certificationAccessibilityWheelchair":"Info","shortDescriptionAccessibilityAllGenerations":"Deutsche Beschreibung von shortDescriptionAccessibilityAllGenerations","shortDescriptionAccessibilityAllergic":"Deutsche Beschreibung von shortDescriptionAccessibilityAllergic","shortDescriptionAccessibilityDeaf":"Deutsche Beschreibung von shortDescriptionAccessibilityDeaf","shortDescriptionAccessibilityMental":"Deutsche Beschreibung von shortDescriptionAccessibilityMental","shortDescriptionAccessibilityVisual":"Deutsche Beschreibung von shortDescriptionAccessibilityVisual","shortDescriptionAccessibilityWalking":"Deutsche Beschreibung von shortDescriptionAccessibilityWalking"}', + ], + ], + 'tx_thuecat_town' => [ + 0 => [ + 'uid' => '1', + 'pid' => '3', + 'title' => 'Beispielstadt', + 'description' => 'Die Beschreibung der Stadt', + ], + ], + 'tx_thuecat_parking_facility' => [ + 0 => [ + 'uid' => '1', + 'pid' => '3', + 'title' => 'Parkhaus Domplatz', + 'address' => '{"street":"Bechtheimer Str. 1","zip":"99084","city":"Erfurt","email":"info@stadtwerke-erfurt.de","phone":"+49 361 5640","fax":"","geo":{"latitude":50.977648905044,"longitude":11.022127985954299}}', + ], + 1 => [ + 'uid' => '2', + 'pid' => '3', + 'title' => 'Q-Park Anger 1 Parkhaus', + 'address' => '{"street":"Anger 1","zip":"99084","city":"Erfurt","email":"servicecenter@q-park.de","phone":"+49 218 18190290","fax":"","geo":{"latitude":50.977999330565794,"longitude":11.037503264052475}}', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Frontend/TouristAttractions.xml b/Tests/Functional/Fixtures/Frontend/TouristAttractions.xml deleted file mode 100644 index 6708c57..0000000 --- a/Tests/Functional/Fixtures/Frontend/TouristAttractions.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - 1 - 3 - Erste Attraktion - Die Beschreibung der Attraktion - 1 - [{"mainImage":true,"type":"image","title":"Erfurt-Dom und Severikirche-beleuchtet.jpg","description":"","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159216\/Preview-1280x0\/image","copyrightYear":2016,"author":"Image Author","license":{"type":"https:\/\/creativecommons.org\/licenses\/by\/4.0\/","author":""}},{"mainImage":false,"type":"image","title":"Erfurt-Dom-und-Severikirche.jpg","description":"Sicht auf Dom St. Marien, St. Severikirche sowie die davor liegenden Klostergeb\u00e4ude und einem Ausschnitt des Biergartens umgeben von einem d\u00e4mmerungsverf\u00e4rten Himmel","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159186\/Preview-1280x0\/image","copyrightYear":2020,"license":{"type":"https:\/\/creativecommons.org\/licenses\/by\/4.0\/","author":""}},{"mainImage":false,"type":"image","title":"Erfurt-Dom und Severikirche-beleuchtet.jpg","description":"","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159216\/Preview-1280x0\/image","copyrightYear":2016,"license":{"type":"https:\/\/creativecommons.org\/licenses\/by\/4.0\/","author":""}}] - [{"opens":"09:30:00","closes":"18:00:00","from":{"date":"2021-05-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2021-10-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Saturday","Friday","Thursday","Tuesday","Monday","Wednesday"]},{"opens":"13:00:00","closes":"18:00:00","from":{"date":"2021-05-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2021-10-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Sunday"]},{"opens":"09:30:00","closes":"17:00:00","from":{"date":"2021-11-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2022-04-30 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Saturday","Friday","Thursday","Tuesday","Monday","Wednesday"]},{"opens":"13:00:00","closes":"17:00:00","from":{"date":"2021-11-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2022-04-30 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Sunday","PublicHolidays"]}] -
{"street":"Beispielstraße 1a","zip":"99084","city":"Beispielstadt","email":"example@example.com","phone":"(0)30 23125 000","fax":"","geo":{"latitude":50.975955358589545,"longitude":11.023667024961856}}
- https://example.com/attraction - [{"type":"GuidedTourOffer","title":"F\u00fchrungen","description":"Immer samstags, um 11:15 Uhr findet eine \u00f6ffentliche F\u00fchrung durch das Museum statt. Dauer etwa 90 Minuten","prices":[{"title":"Erwachsene","description":"","price":8,"currency":"EUR","rule":"PerPerson"},{"title":"Erm\u00e4\u00dfigt","description":"als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt","price":5,"currency":"EUR","rule":"PerPerson"}]},{"type":"EntryOffer","title":"Eintritt","description":"Schulklassen und Kitagruppen im Rahmen des Unterrichts: Eintritt frei\nAn jedem ersten Dienstag im Monat: Eintritt frei","prices":[{"title":"Erm\u00e4\u00dfigt","description":"als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt","price":5,"currency":"EUR","rule":"PerPerson"},{"title":"Familienkarte","description":"","price":17,"currency":"EUR","rule":"PerGroup"},{"title":"ErfurtCard","description":"","price":14.9,"currency":"EUR","rule":"PerPackage"},{"title":"Erwachsene","description":"","price":8,"currency":"EUR","rule":"PerPerson"}]}] - Highlight - 11. Jh - Toilets,DisabledToilets,NappyChangingArea,FamilyAndChildFriendly - Playground,SeatingPossibilitiesRestArea,SouvenirShop,PlayCornerOrPlayArea - MuseumShop,PedagogicalOffer,ZeroInformationMuseumService - ArchitectureOfHomelandSecurity,ArtDeco,ArtNouveau,Baroque,BauhausStyle,Brutalism,Classicism,Constructivism,CriticalRegionalism,Deconstructivism,Expressionism,Functionalism,GothicArt,GothicRevival,HighTechArchitecture,Historicism,InternationalStyle,Minimalism,Modernism,Neoclassicism,Neorenaissance,NewBuilding,NewObjectivity,OrganicConstruction,PostWarModernism,PostmodernAge,Rationalism,Renaissance,Rococo,RomanesquePeriod,ZeroInformationArchitecturalStyle - BicycleLockersEnumMem,BicycleStandsEnumMem,BicycleStandsBicycleLockersEnumMem,BusParkCoachParkEnumMem,EbikeChargingStationEnumMem,ElectricVehicleCarChargingStationEnumMem,ZeroSpecialTrafficInfrastructure - AliPay,AmericanExpress,ApplePay,CashPayment,EC,InstantBankTransfer,Invoice,MasterCard,PayPal,Visa - AppForMobileDevices,AudioGuide,AugmentedReality,VideoGuide,VirtuellReality,ZeroDigitalOffer - PhotoLicenceFeeRequired,TakingPicturesPermitted,ZeroPhotography,some free text value for photography - Tiere sind im Gebäude nicht gestattet, ausgenommen sind Blinden- und Blindenbegleithunde. - German,English,French - 250:MTR - 1,2 - {"accessibilityCertificationStatus":"AccessibilityChecked","accessibilitySearchCriteria":{"facilityAccessibilityDeaf":["AudioInductionLoop","FlashingSignalCallWaitingDoor","SpecialOffersDeafPeople","SpecialOffersHearingImpairment","VisualConfirmationDistressCallElevator"],"facilityAccessibilityMental":["ColoredOrPictorialGuidanceSystem","InformationInEasyLanguage","InformationWithPictogramsOrPictures"],"facilityAccessibilityVisual":["AssistanceDogsWelcome","GuidanceSystemWithFloorIndicators","InformationBrailleOrPrismaticFont","OffersInPictoralLanguage","SpecialOffersBlindPeople","SpecialOffersVisualImpairment","TactileOffers","VisuallyContrastingStepEdges"],"facilityAccessibilityWalking":["AllRoomsStepFreeAccess","EightyCMWidthPassageWays","EntryAidSwimmingPool","GrabRailInShower","HandrailsOnBothSidesOfAllStaircases","HingedGrabRailToilet","LateralAccessibleToilet","MinumumManoeuvringSpaceShower","NinetyCMWidthPassageWays","NursingBed","ParkingPeopleWithDisabilities","SeventyCMWidthPassageWays","ShowerSeat","SpecialOffersWalkingImpairment","SpecialOffersWheelchairUsers","StepFreeAccess","StepFreeShower","ToiletsPeopleWithDisabilities"]},"certificationAccessibilityDeaf":"Full","certificationAccessibilityMental":"None","certificationAccessibilityPartiallyDeaf":"None","certificationAccessibilityPartiallyVisual":"Info","certificationAccessibilityVisual":"None","certificationAccessibilityWalking":"Info","certificationAccessibilityWheelchair":"Info","shortDescriptionAccessibilityAllGenerations":"Deutsche Beschreibung von shortDescriptionAccessibilityAllGenerations","shortDescriptionAccessibilityAllergic":"Deutsche Beschreibung von shortDescriptionAccessibilityAllergic","shortDescriptionAccessibilityDeaf":"Deutsche Beschreibung von shortDescriptionAccessibilityDeaf","shortDescriptionAccessibilityMental":"Deutsche Beschreibung von shortDescriptionAccessibilityMental","shortDescriptionAccessibilityVisual":"Deutsche Beschreibung von shortDescriptionAccessibilityVisual","shortDescriptionAccessibilityWalking":"Deutsche Beschreibung von shortDescriptionAccessibilityWalking"} -
- - 1 - 3 - Beispielstadt - Die Beschreibung der Stadt - - - 1 - 3 - Parkhaus Domplatz -
{"street":"Bechtheimer Str. 1","zip":"99084","city":"Erfurt","email":"info@stadtwerke-erfurt.de","phone":"+49 361 5640","fax":"","geo":{"latitude":50.977648905044,"longitude":11.022127985954299}}
-
- - 2 - 3 - Q-Park Anger 1 Parkhaus -
{"street":"Anger 1","zip":"99084","city":"Erfurt","email":"servicecenter@q-park.de","phone":"+49 218 18190290","fax":"","geo":{"latitude":50.977999330565794,"longitude":11.037503264052475}}
-
-
- diff --git a/Tests/Functional/Fixtures/Frontend/TouristAttractionsForIsAccessibleForFree.php b/Tests/Functional/Fixtures/Frontend/TouristAttractionsForIsAccessibleForFree.php new file mode 100644 index 0000000..31a6a05 --- /dev/null +++ b/Tests/Functional/Fixtures/Frontend/TouristAttractionsForIsAccessibleForFree.php @@ -0,0 +1,62 @@ + [ + 0 => [ + 'uid' => '2', + 'pid' => '3', + 'title' => 'Attraktion mit false', + 'description' => '', + 'town' => '0', + 'media' => '', + 'opening_hours' => '', + 'address' => '', + 'offers' => '', + 'slogan' => '', + 'start_of_construction' => '', + 'sanitation' => '', + 'other_service' => '', + 'museum_service' => '', + 'architectural_style' => '', + 'traffic_infrastructure' => '', + 'payment_accepted' => '', + 'digital_offer' => '', + 'photography' => '', + 'pets_allowed' => '', + 'is_accessible_for_free' => 'false', + ], + 1 => [ + 'uid' => '3', + 'pid' => '3', + 'title' => 'Attraktion mit true', + 'description' => '', + 'town' => '0', + 'media' => '', + 'opening_hours' => '', + 'address' => '', + 'offers' => '', + 'slogan' => '', + 'start_of_construction' => '', + 'sanitation' => '', + 'other_service' => '', + 'museum_service' => '', + 'architectural_style' => '', + 'traffic_infrastructure' => '', + 'payment_accepted' => '', + 'digital_offer' => '', + 'photography' => '', + 'pets_allowed' => '', + 'is_accessible_for_free' => 'true', + ], + ], + 'tx_thuecat_town' => [ + 0 => [ + 'uid' => '1', + 'pid' => '3', + 'title' => 'Beispielstadt', + 'description' => 'Die Beschreibung der Stadt', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Frontend/TouristAttractionsForIsAccessibleForFree.xml b/Tests/Functional/Fixtures/Frontend/TouristAttractionsForIsAccessibleForFree.xml deleted file mode 100644 index ad4a306..0000000 --- a/Tests/Functional/Fixtures/Frontend/TouristAttractionsForIsAccessibleForFree.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - 2 - 3 - Attraktion mit false - - 0 - - -
- - - - - - - - - - - - - false -
- - 3 - 3 - Attraktion mit true - - 0 - - -
- - - - - - - - - - - - - true -
- - 1 - 3 - Beispielstadt - Die Beschreibung der Stadt - -
- diff --git a/Tests/Functional/Fixtures/Frontend/TouristAttractionsForPets.php b/Tests/Functional/Fixtures/Frontend/TouristAttractionsForPets.php new file mode 100644 index 0000000..0def6ba --- /dev/null +++ b/Tests/Functional/Fixtures/Frontend/TouristAttractionsForPets.php @@ -0,0 +1,60 @@ + [ + 0 => [ + 'uid' => '2', + 'pid' => '3', + 'title' => 'Attraktion mit pets_allowed = false', + 'description' => '', + 'town' => '0', + 'media' => '', + 'opening_hours' => '', + 'address' => '', + 'offers' => '', + 'slogan' => '', + 'start_of_construction' => '', + 'sanitation' => '', + 'other_service' => '', + 'museum_service' => '', + 'architectural_style' => '', + 'traffic_infrastructure' => '', + 'payment_accepted' => '', + 'digital_offer' => '', + 'photography' => '', + 'pets_allowed' => 'false', + ], + 1 => [ + 'uid' => '3', + 'pid' => '3', + 'title' => 'Attraktion mit pets_allowed = true', + 'description' => '', + 'town' => '0', + 'media' => '', + 'opening_hours' => '', + 'address' => '', + 'offers' => '', + 'slogan' => '', + 'start_of_construction' => '', + 'sanitation' => '', + 'other_service' => '', + 'museum_service' => '', + 'architectural_style' => '', + 'traffic_infrastructure' => '', + 'payment_accepted' => '', + 'digital_offer' => '', + 'photography' => '', + 'pets_allowed' => 'true', + ], + ], + 'tx_thuecat_town' => [ + 0 => [ + 'uid' => '1', + 'pid' => '3', + 'title' => 'Beispielstadt', + 'description' => 'Die Beschreibung der Stadt', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Frontend/TouristAttractionsForPets.xml b/Tests/Functional/Fixtures/Frontend/TouristAttractionsForPets.xml deleted file mode 100644 index bb86587..0000000 --- a/Tests/Functional/Fixtures/Frontend/TouristAttractionsForPets.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - 2 - 3 - Attraktion mit pets_allowed = false - - 0 - - -
- - - - - - - - - - - - false -
- - 3 - 3 - Attraktion mit pets_allowed = true - - 0 - - -
- - - - - - - - - - - - true -
- - 1 - 3 - Beispielstadt - Die Beschreibung der Stadt - -
- diff --git a/Tests/Functional/Fixtures/Frontend/TouristAttractionsForPublicAccess.php b/Tests/Functional/Fixtures/Frontend/TouristAttractionsForPublicAccess.php new file mode 100644 index 0000000..d9495cc --- /dev/null +++ b/Tests/Functional/Fixtures/Frontend/TouristAttractionsForPublicAccess.php @@ -0,0 +1,60 @@ + [ + 0 => [ + 'uid' => '2', + 'pid' => '3', + 'title' => 'Attraktion mit public_access = false', + 'description' => '', + 'town' => '0', + 'media' => '', + 'opening_hours' => '', + 'address' => '', + 'offers' => '', + 'slogan' => '', + 'start_of_construction' => '', + 'sanitation' => '', + 'other_service' => '', + 'museum_service' => '', + 'architectural_style' => '', + 'traffic_infrastructure' => '', + 'payment_accepted' => '', + 'digital_offer' => '', + 'photography' => '', + 'public_access' => 'false', + ], + 1 => [ + 'uid' => '3', + 'pid' => '3', + 'title' => 'Attraktion mit public_access = true', + 'description' => '', + 'town' => '0', + 'media' => '', + 'opening_hours' => '', + 'address' => '', + 'offers' => '', + 'slogan' => '', + 'start_of_construction' => '', + 'sanitation' => '', + 'other_service' => '', + 'museum_service' => '', + 'architectural_style' => '', + 'traffic_infrastructure' => '', + 'payment_accepted' => '', + 'digital_offer' => '', + 'photography' => '', + 'public_access' => 'true', + ], + ], + 'tx_thuecat_town' => [ + 0 => [ + 'uid' => '1', + 'pid' => '3', + 'title' => 'Beispielstadt', + 'description' => 'Die Beschreibung der Stadt', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Frontend/TouristAttractionsForPublicAccess.xml b/Tests/Functional/Fixtures/Frontend/TouristAttractionsForPublicAccess.xml deleted file mode 100644 index 5604dd9..0000000 --- a/Tests/Functional/Fixtures/Frontend/TouristAttractionsForPublicAccess.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - 2 - 3 - Attraktion mit public_access = false - - 0 - - -
- - - - - - - - - - - - false -
- - 3 - 3 - Attraktion mit public_access = true - - 0 - - -
- - - - - - - - - - - - true -
- - 1 - 3 - Beispielstadt - Die Beschreibung der Stadt - -
- diff --git a/Tests/Functional/Fixtures/Frontend/TouristAttractionsOpeningHours.php b/Tests/Functional/Fixtures/Frontend/TouristAttractionsOpeningHours.php new file mode 100644 index 0000000..dcab1b9 --- /dev/null +++ b/Tests/Functional/Fixtures/Frontend/TouristAttractionsOpeningHours.php @@ -0,0 +1,14 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '3', + 'title' => 'Erste Attraktion', + 'description' => 'Die Beschreibung der Attraktion', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Frontend/TouristAttractionsOpeningHours.xml b/Tests/Functional/Fixtures/Frontend/TouristAttractionsOpeningHours.xml deleted file mode 100644 index d2c3857..0000000 --- a/Tests/Functional/Fixtures/Frontend/TouristAttractionsOpeningHours.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - 1 - 3 - Erste Attraktion - Die Beschreibung der Attraktion - - - diff --git a/Tests/Functional/Fixtures/Import/BackendUser.php b/Tests/Functional/Fixtures/Import/BackendUser.php new file mode 100644 index 0000000..0f878d0 --- /dev/null +++ b/Tests/Functional/Fixtures/Import/BackendUser.php @@ -0,0 +1,26 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1366642540', + 'username' => 'admin', + 'password' => '$1$tCrlLajZ$C0sikFQQ3SWaFAZ1Me0Z/1', + 'admin' => '1', + 'disable' => '0', + 'starttime' => '0', + 'endtime' => '0', + 'options' => '0', + 'crdate' => '1366642540', + 'workspace_perms' => '1', + 'deleted' => '0', + 'TSconfig' => null, + 'lastlogin' => '1371033743', + 'workspace_id' => '0', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Import/ImportWithMultipleReferencesToSameObject.csv b/Tests/Functional/Fixtures/Import/ImportWithMultipleReferencesToSameObject.csv deleted file mode 100644 index 868d981..0000000 --- a/Tests/Functional/Fixtures/Import/ImportWithMultipleReferencesToSameObject.csv +++ /dev/null @@ -1,33 +0,0 @@ -"tx_thuecat_import_log",,,,,,, -,"uid","pid","configuration",,,, -,1,0,1,,,, -"tx_thuecat_import_log_entry",,,,,,, -,"uid","pid","import_log","record_uid","table_name","insertion","errors" -,1,0,1,1,"tx_thuecat_organisation",1,"[]" -,2,0,1,1,"tx_thuecat_town",1,"[]" -,3,0,1,1,"tx_thuecat_parking_facility",1,"[]" -,4,0,1,2,"tx_thuecat_parking_facility",0,"[]" -,5,0,1,3,"tx_thuecat_parking_facility",0,"[]" -,6,0,1,1,"tx_thuecat_tourist_attraction",1,"[]" -,7,0,1,2,"tx_thuecat_tourist_attraction",0,"[]" -,8,0,1,3,"tx_thuecat_tourist_attraction",1,"[]" -,9,0,1,4,"tx_thuecat_tourist_attraction",0,"[]" -,10,0,1,5,"tx_thuecat_tourist_attraction",0,"[]" -"tx_thuecat_organisation",,,,,,, -,"uid","pid","remote_id","title",,, -,1,10,"https://thuecat.org/resources/018132452787-ngbe","Erfurt Tourismus und Marketing GmbH",,, -"tx_thuecat_town",,,,,,, -,"uid","pid","remote_id","title","managed_by",, -,1,10,"https://thuecat.org/resources/043064193523-jcyt","Erfurt",1,, -"tx_thuecat_parking_facility",,,,,,, -,"uid","pid","sys_language_uid","remote_id","title","managed_by", -,1,10,0,"https://thuecat.org/resources/396420044896-drzt","Parkhaus Domplatz",1, -,2,10,1,"https://thuecat.org/resources/396420044896-drzt","Car park Domplatz",1, -,3,10,2,"https://thuecat.org/resources/396420044896-drzt","Parking Domplatz",1, -"tx_thuecat_tourist_attraction",,,,,,, -,"uid","pid","sys_language_uid","remote_id","title","managed_by","town" -,1,10,0,"https://thuecat.org/resources/835224016581-dara","Dom St. Marien",1,1 -,2,10,1,"https://thuecat.org/resources/835224016581-dara","Cathedral of St. Mary",1,1 -,3,10,0,"https://thuecat.org/resources/165868194223-zmqf","Alte Synagoge",1,1 -,4,10,1,"https://thuecat.org/resources/165868194223-zmqf","Old Synagogue",1,1 -,5,10,2,"https://thuecat.org/resources/165868194223-zmqf","La vieille synagogue",1,1 diff --git a/Tests/Functional/Fixtures/Import/ImportWithMultipleReferencesToSameObject.xml b/Tests/Functional/Fixtures/Import/ImportWithMultipleReferencesToSameObject.php similarity index 57% rename from Tests/Functional/Fixtures/Import/ImportWithMultipleReferencesToSameObject.xml rename to Tests/Functional/Fixtures/Import/ImportWithMultipleReferencesToSameObject.php index 3d5e735..4a18bb2 100644 --- a/Tests/Functional/Fixtures/Import/ImportWithMultipleReferencesToSameObject.xml +++ b/Tests/Functional/Fixtures/Import/ImportWithMultipleReferencesToSameObject.php @@ -1,51 +1,39 @@ - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 4 - Rootpage - 1 - - - 10 - 1 - 1613400587 - 1613400558 - 1 - 254 - Storage folder - + - 1 - 0 - English - en-us-gb - en - +declare(strict_types=1); - - 2 - 0 - French - fr - fr - +use TYPO3\CMS\Core\Domain\Repository\PageRepository; - - 1 - 0 - 1613400587 - 1613400558 - 1 - 0 - Attractions within Town Erfurt - static - +return [ + 'pages' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_DEFAULT, + 'title' => 'Rootpage', + 'is_siteroot' => '1', + ], + 1 => [ + 'uid' => '10', + 'pid' => '1', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_SYSFOLDER, + 'title' => 'Storage folder', + ], + ], + 'tx_thuecat_import_configuration' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'disable' => '0', + 'title' => 'Attractions within Town Erfurt', + 'type' => 'static', + 'configuration' => ' @@ -80,6 +68,7 @@ - ]]> - - + ', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Import/ImportsContainsPlace.csv b/Tests/Functional/Fixtures/Import/ImportsContainsPlace.csv deleted file mode 100644 index 4d34c99..0000000 --- a/Tests/Functional/Fixtures/Import/ImportsContainsPlace.csv +++ /dev/null @@ -1,16 +0,0 @@ -"tx_thuecat_tourist_attraction",,,,, -,"uid","pid","sys_language_uid","remote_id","title" -,1,10,0,"https://thuecat.org/resources/835224016581-dara","Dom St. Marien" -,2,10,1,"https://thuecat.org/resources/835224016581-dara","Cathedral of St. Mary" -,3,10,0,"https://thuecat.org/resources/165868194223-zmqf","Alte Synagoge" -,4,10,1,"https://thuecat.org/resources/165868194223-zmqf","Old Synagogue" -,5,10,2,"https://thuecat.org/resources/165868194223-zmqf","La vieille synagogue" -,6,10,0,"https://thuecat.org/resources/215230952334-yyno","Krämerbrücke" -,7,10,1,"https://thuecat.org/resources/215230952334-yyno","Merchants' Bridge" -,8,10,2,"https://thuecat.org/resources/215230952334-yyno","Pont de l'épicier" -"tx_thuecat_organisation",,,,, -,"uid","pid","remote_id","title", -,1,10,"https://thuecat.org/resources/018132452787-ngbe","Erfurt Tourismus und Marketing GmbH", -"tx_thuecat_town",,,,, -,"uid","pid","remote_id","title", -,1,10,"https://thuecat.org/resources/043064193523-jcyt","Erfurt", diff --git a/Tests/Functional/Fixtures/Import/ImportsContainsPlace.php b/Tests/Functional/Fixtures/Import/ImportsContainsPlace.php new file mode 100644 index 0000000..76b4405 --- /dev/null +++ b/Tests/Functional/Fixtures/Import/ImportsContainsPlace.php @@ -0,0 +1,53 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_DEFAULT, + 'title' => 'Rootpage', + 'is_siteroot' => '1', + ], + 1 => [ + 'uid' => '10', + 'pid' => '1', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_SYSFOLDER, + 'title' => 'Storage folder', + ], + ], + 'tx_thuecat_import_configuration' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'disable' => '0', + 'title' => 'Contains Place', + 'type' => 'containsPlace', + 'configuration' => ' + + + + + + 10 + + + 043064193523-contains + + + + + ', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Import/ImportsContainsPlace.xml b/Tests/Functional/Fixtures/Import/ImportsContainsPlace.xml deleted file mode 100644 index e756748..0000000 --- a/Tests/Functional/Fixtures/Import/ImportsContainsPlace.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 4 - Rootpage - 1 - - - 10 - 1 - 1613400587 - 1613400558 - 1 - 254 - Storage folder - - - - 1 - 0 - English - en-us-gb - en - - - - 2 - 0 - French - fr - fr - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 0 - Contains Place - containsPlace - - - - - - - 10 - - - 043064193523-contains - - - - - ]]> - - diff --git a/Tests/Functional/Fixtures/Import/ImportsFollowingRecordsInCaseOfAnMappingException.csv b/Tests/Functional/Fixtures/Import/ImportsFollowingRecordsInCaseOfAnMappingException.csv deleted file mode 100644 index b8d795c..0000000 --- a/Tests/Functional/Fixtures/Import/ImportsFollowingRecordsInCaseOfAnMappingException.csv +++ /dev/null @@ -1,18 +0,0 @@ -"tx_thuecat_tourist_attraction",,,,,,,, -,"uid","pid","sys_language_uid","remote_id","title",,, -,1,10,0,"https://thuecat.org/resources/165868194223-zmqf","Alte Synagoge",,, -,2,10,1,"https://thuecat.org/resources/165868194223-zmqf","Old Synagogue",,, -,3,10,2,"https://thuecat.org/resources/165868194223-zmqf","La vieille synagogue",,, -"tx_thuecat_import_log",,,,,,,, -,"uid","pid","configuration","log_entries",,,, -,1,0,1,0,,,, -"tx_thuecat_import_log_entry",,,,,,,, -,"uid","pid","type","import_log","record_uid","table_name","insertion","errors" -,1,0,"mappingError",1,0,,0,"[""Could not map incoming JSON-LD to target object: Failed to parse time string (18:00: 00) at position 5 (:): Unexpected character""]" -,2,0,"mappingError",1,0,,0,"[""Could not map incoming JSON-LD to target object: Failed to parse time string (18:00: 00) at position 5 (:): Unexpected character""]" -,3,0,"mappingError",1,0,,0,"[""Could not map incoming JSON-LD to target object: Failed to parse time string (18:00: 00) at position 5 (:): Unexpected character""]" -,4,0,"savingEntity",1,1,"tx_thuecat_organisation",1,"[]" -,5,0,"savingEntity",1,1,"tx_thuecat_town",0,"[]" -,6,0,"savingEntity",1,1,"tx_thuecat_tourist_attraction",1,"[]" -,7,0,"savingEntity",1,2,"tx_thuecat_tourist_attraction",0,"[]" -,8,0,"savingEntity",1,3,"tx_thuecat_tourist_attraction",0,"[]" diff --git a/Tests/Functional/Fixtures/Import/ImportsFollowingRecordsInCaseOfAnMappingException.xml b/Tests/Functional/Fixtures/Import/ImportsFollowingRecordsInCaseOfAnMappingException.php similarity index 51% rename from Tests/Functional/Fixtures/Import/ImportsFollowingRecordsInCaseOfAnMappingException.xml rename to Tests/Functional/Fixtures/Import/ImportsFollowingRecordsInCaseOfAnMappingException.php index c78bae8..4c382b5 100644 --- a/Tests/Functional/Fixtures/Import/ImportsFollowingRecordsInCaseOfAnMappingException.xml +++ b/Tests/Functional/Fixtures/Import/ImportsFollowingRecordsInCaseOfAnMappingException.php @@ -1,51 +1,39 @@ - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 4 - Rootpage - 1 - - - 10 - 1 - 1613400587 - 1613400558 - 1 - 254 - Storage folder - + - 1 - 0 - English - en-us-gb - en - +declare(strict_types=1); - - 2 - 0 - French - fr - fr - +use TYPO3\CMS\Core\Domain\Repository\PageRepository; - - 1 - 0 - 1613400587 - 1613400558 - 1 - 0 - Import With Exceptions - static - +return [ + 'pages' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_DEFAULT, + 'title' => 'Rootpage', + 'is_siteroot' => '1', + ], + 1 => [ + 'uid' => '10', + 'pid' => '1', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_SYSFOLDER, + 'title' => 'Storage folder', + ], + ], + 'tx_thuecat_import_configuration' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'disable' => '0', + 'title' => 'Import With Exceptions', + 'type' => 'static', + 'configuration' => ' @@ -81,19 +69,20 @@ - ]]> - - - - 1 - 10 - 1613401129 - 1613401129 - 1 - 0 - https://thuecat.org/resources/043064193523-jcyt - 1 - 0 - Erfurt - - + ', + ], + ], + 'tx_thuecat_town' => [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'tstamp' => '1613401129', + 'crdate' => '1613401129', + 'disable' => '0', + 'remote_id' => 'https://thuecat.org/resources/043064193523-jcyt', + 'managed_by' => '1', + 'tourist_information' => '0', + 'title' => 'Erfurt', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Import/ImportsFollowingRecordsInCaseOfAnMappingExceptionOldPhp.csv b/Tests/Functional/Fixtures/Import/ImportsFollowingRecordsInCaseOfAnMappingExceptionOldPhp.csv deleted file mode 100644 index 3de3703..0000000 --- a/Tests/Functional/Fixtures/Import/ImportsFollowingRecordsInCaseOfAnMappingExceptionOldPhp.csv +++ /dev/null @@ -1,18 +0,0 @@ -"tx_thuecat_tourist_attraction",,,,,,,, -,"uid","pid","sys_language_uid","remote_id","title",,, -,1,10,0,"https://thuecat.org/resources/165868194223-zmqf","Alte Synagoge",,, -,2,10,1,"https://thuecat.org/resources/165868194223-zmqf","Old Synagogue",,, -,3,10,2,"https://thuecat.org/resources/165868194223-zmqf","La vieille synagogue",,, -"tx_thuecat_import_log",,,,,,,, -,"uid","pid","configuration","log_entries",,,, -,1,0,1,0,,,, -"tx_thuecat_import_log_entry",,,,,,,, -,"uid","pid","type","import_log","record_uid","table_name","insertion","errors" -,1,0,"mappingError",1,0,,0,"[""Could not map incoming JSON-LD to target object: DateTimeImmutable::__construct(): Failed to parse time string (18:00: 00) at position 5 (:): Unexpected character""]" -,2,0,"mappingError",1,0,,0,"[""Could not map incoming JSON-LD to target object: DateTimeImmutable::__construct(): Failed to parse time string (18:00: 00) at position 5 (:): Unexpected character""]" -,3,0,"mappingError",1,0,,0,"[""Could not map incoming JSON-LD to target object: DateTimeImmutable::__construct(): Failed to parse time string (18:00: 00) at position 5 (:): Unexpected character""]" -,4,0,"savingEntity",1,1,"tx_thuecat_organisation",1,"[]" -,5,0,"savingEntity",1,1,"tx_thuecat_town",0,"[]" -,6,0,"savingEntity",1,1,"tx_thuecat_tourist_attraction",1,"[]" -,7,0,"savingEntity",1,2,"tx_thuecat_tourist_attraction",0,"[]" -,8,0,"savingEntity",1,3,"tx_thuecat_tourist_attraction",0,"[]" diff --git a/Tests/Functional/Fixtures/Import/ImportsFollowingRecordsInCaseOfAnMappingExceptionOldPhp.php b/Tests/Functional/Fixtures/Import/ImportsFollowingRecordsInCaseOfAnMappingExceptionOldPhp.php new file mode 100644 index 0000000..d4a2fc1 --- /dev/null +++ b/Tests/Functional/Fixtures/Import/ImportsFollowingRecordsInCaseOfAnMappingExceptionOldPhp.php @@ -0,0 +1,119 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'sys_language_uid' => '0', + 'remote_id' => 'https://thuecat.org/resources/165868194223-zmqf', + 'title' => 'Alte Synagoge', + ], + 1 => [ + 'uid' => '2', + 'pid' => '10', + 'sys_language_uid' => '1', + 'remote_id' => 'https://thuecat.org/resources/165868194223-zmqf', + 'title' => 'Old Synagogue', + ], + 2 => [ + 'uid' => '3', + 'pid' => '10', + 'sys_language_uid' => '2', + 'remote_id' => 'https://thuecat.org/resources/165868194223-zmqf', + 'title' => 'La vieille synagogue', + ], + ], + 'tx_thuecat_import_log' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'configuration' => '1', + 'log_entries' => '0', + ], + ], + 'tx_thuecat_import_log_entry' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'type' => 'mappingError', + 'import_log' => '1', + 'record_uid' => '0', + 'table_name' => '', + 'insertion' => '0', + 'errors' => '["Could not map incoming JSON-LD to target object: DateTimeImmutable::__construct(): Failed to parse time string (18:00: 00) at position 5 (:): Unexpected character"]', + ], + 1 => [ + 'uid' => '2', + 'pid' => '0', + 'type' => 'mappingError', + 'import_log' => '1', + 'record_uid' => '0', + 'table_name' => '', + 'insertion' => '0', + 'errors' => '["Could not map incoming JSON-LD to target object: DateTimeImmutable::__construct(): Failed to parse time string (18:00: 00) at position 5 (:): Unexpected character"]', + ], + 2 => [ + 'uid' => '3', + 'pid' => '0', + 'type' => 'mappingError', + 'import_log' => '1', + 'record_uid' => '0', + 'table_name' => '', + 'insertion' => '0', + 'errors' => '["Could not map incoming JSON-LD to target object: DateTimeImmutable::__construct(): Failed to parse time string (18:00: 00) at position 5 (:): Unexpected character"]', + ], + 3 => [ + 'uid' => '4', + 'pid' => '0', + 'type' => 'savingEntity', + 'import_log' => '1', + 'record_uid' => '1', + 'table_name' => 'tx_thuecat_organisation', + 'insertion' => '1', + 'errors' => '[]', + ], + 4 => [ + 'uid' => '5', + 'pid' => '0', + 'type' => 'savingEntity', + 'import_log' => '1', + 'record_uid' => '1', + 'table_name' => 'tx_thuecat_town', + 'insertion' => '0', + 'errors' => '[]', + ], + 5 => [ + 'uid' => '6', + 'pid' => '0', + 'type' => 'savingEntity', + 'import_log' => '1', + 'record_uid' => '1', + 'table_name' => 'tx_thuecat_tourist_attraction', + 'insertion' => '1', + 'errors' => '[]', + ], + 6 => [ + 'uid' => '7', + 'pid' => '0', + 'type' => 'savingEntity', + 'import_log' => '1', + 'record_uid' => '2', + 'table_name' => 'tx_thuecat_tourist_attraction', + 'insertion' => '0', + 'errors' => '[]', + ], + 7 => [ + 'uid' => '8', + 'pid' => '0', + 'type' => 'savingEntity', + 'import_log' => '1', + 'record_uid' => '3', + 'table_name' => 'tx_thuecat_tourist_attraction', + 'insertion' => '0', + 'errors' => '[]', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Import/ImportsFreshOrganization.csv b/Tests/Functional/Fixtures/Import/ImportsFreshOrganization.csv deleted file mode 100644 index 72ebe26..0000000 --- a/Tests/Functional/Fixtures/Import/ImportsFreshOrganization.csv +++ /dev/null @@ -1,9 +0,0 @@ -tx_thuecat_organisation -,"uid","pid","remote_id","title" -,1,11,"https://thuecat.org/resources/018132452787-ngbe","Erfurt Tourismus und Marketing GmbH" -tx_thuecat_import_log -,"uid","pid","configuration" -,1,0,1 -tx_thuecat_import_log_entry -,"uid","pid","import_log","record_uid","table_name","insertion","errors" -,1,0,1,1,"tx_thuecat_organisation",1,"[]" diff --git a/Tests/Functional/Fixtures/Import/ImportsFreshOrganization.xml b/Tests/Functional/Fixtures/Import/ImportsFreshOrganization.php similarity index 54% rename from Tests/Functional/Fixtures/Import/ImportsFreshOrganization.xml rename to Tests/Functional/Fixtures/Import/ImportsFreshOrganization.php index 8ab2f77..c89b391 100644 --- a/Tests/Functional/Fixtures/Import/ImportsFreshOrganization.xml +++ b/Tests/Functional/Fixtures/Import/ImportsFreshOrganization.php @@ -1,35 +1,39 @@ - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 4 - Rootpage - 1 - - - 11 - 1 - 1613400587 - 1613400558 - 1 - 254 - Storage folder - + - 1 - 0 - 1613400587 - 1613400558 - 1 - 0 - Single Fresh Organisation - static - +declare(strict_types=1); + +use TYPO3\CMS\Core\Domain\Repository\PageRepository; + +return [ + 'pages' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_DEFAULT, + 'title' => 'Rootpage', + 'is_siteroot' => '1', + ], + 1 => [ + 'uid' => '11', + 'pid' => '1', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_SYSFOLDER, + 'title' => 'Storage folder', + ], + ], + 'tx_thuecat_import_configuration' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'disable' => '0', + 'title' => 'Single Fresh Organisation', + 'type' => 'static', + 'configuration' => ' @@ -55,6 +59,7 @@ - ]]> - - + ', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Import/ImportsSyncScope.csv b/Tests/Functional/Fixtures/Import/ImportsSyncScope.csv deleted file mode 100644 index 9df311f..0000000 --- a/Tests/Functional/Fixtures/Import/ImportsSyncScope.csv +++ /dev/null @@ -1,10 +0,0 @@ -"tx_thuecat_tourist_attraction",,,,,,,,,,,, -,"uid","pid","sys_language_uid","l18n_parent","l10n_source","l10n_state","remote_id","title","managed_by","town","address","offers" -,1,10,0,0,0,"\NULL","https://thuecat.org/resources/835224016581-dara","Dom St. Marien",1,1,"{""street"":""Domstufen 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""dominformation@domberg-erfurt.de"",""phone"":""+49 361 6461265"",""fax"":"""",""geo"":{""latitude"":50.975955358589545,""longitude"":11.023667024961856}}","[]" -,2,10,1,1,1,"\NULL","https://thuecat.org/resources/835224016581-dara","Cathedral of St. Mary",1,1,"{""street"":""Domstufen 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""dominformation@domberg-erfurt.de"",""phone"":""+49 361 6461265"",""fax"":"""",""geo"":{""latitude"":50.975955358589545,""longitude"":11.023667024961856}}","[]" -,3,10,0,0,0,"\NULL","https://thuecat.org/resources/165868194223-zmqf","Alte Synagoge",1,1,"{""street"":""Waagegasse 8"",""zip"":""99084"",""city"":""Erfurt"",""email"":""altesynagoge@erfurt.de"",""phone"":""+49 361 6551520"",""fax"":""+49 361 6551669"",""geo"":{""latitude"":50.978765,""longitude"":11.029133}}","[{""types"":[""GuidedTourOffer""],""title"":""F\u00fchrungen"",""description"":""Immer samstags, um 11:15 Uhr findet eine \u00f6ffentliche F\u00fchrung durch das Museum statt. Dauer etwa 90 Minuten"",""prices"":[{""title"":""Erwachsene"",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":""Erm\u00e4\u00dfigt"",""description"":""als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt"",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""}]},{""types"":[""EntryOffer""],""title"":""Eintritt"",""description"":""Schulklassen und Kitagruppen im Rahmen des Unterrichts: Eintritt frei\nAn jedem ersten Dienstag im Monat: Eintritt frei"",""prices"":[{""title"":""Erm\u00e4\u00dfigt"",""description"":""als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt"",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":""Familienkarte"",""description"":"""",""price"":17,""currency"":""EUR"",""rule"":""PerGroup""},{""title"":""ErfurtCard"",""description"":"""",""price"":14.9,""currency"":""EUR"",""rule"":""PerPackage""},{""title"":""Erwachsene"",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""}]}]" -,4,10,1,3,3,"\NULL","https://thuecat.org/resources/165868194223-zmqf","Old Synagogue",1,1,"{""street"":""Waagegasse 8"",""zip"":""99084"",""city"":""Erfurt"",""email"":""altesynagoge@erfurt.de"",""phone"":""+49 361 6551520"",""fax"":""+49 361 6551669"",""geo"":{""latitude"":50.978765,""longitude"":11.029133}}","[{""types"":[""GuidedTourOffer""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":"""",""description"":"""",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""}]},{""types"":[""EntryOffer""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":"""",""description"":"""",""price"":17,""currency"":""EUR"",""rule"":""PerGroup""},{""title"":"""",""description"":"""",""price"":14.9,""currency"":""EUR"",""rule"":""PerPackage""},{""title"":"""",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""}]}]" -,5,10,2,3,3,"\NULL","https://thuecat.org/resources/165868194223-zmqf","La vieille synagogue",1,1,"{""street"":""Waagegasse 8"",""zip"":""99084"",""city"":""Erfurt"",""email"":""altesynagoge@erfurt.de"",""phone"":""+49 361 6551520"",""fax"":""+49 361 6551669"",""geo"":{""latitude"":50.978765,""longitude"":11.029133}}","[{""types"":[""GuidedTourOffer""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":"""",""description"":"""",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""}]},{""types"":[""EntryOffer""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":"""",""description"":"""",""price"":17,""currency"":""EUR"",""rule"":""PerGroup""},{""title"":"""",""description"":"""",""price"":14.9,""currency"":""EUR"",""rule"":""PerPackage""},{""title"":"""",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""}]}]" -,6,10,0,0,0,"\NULL","https://thuecat.org/resources/215230952334-yyno","Krämerbrücke",1,1,"{""street"":""Benediktsplatz 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""service@erfurt-tourismus.de"",""phone"":""+49 361 66 400"",""fax"":"""",""geo"":{""latitude"":50.978772,""longitude"":11.031622}}","[]" -,7,10,1,6,6,"\NULL","https://thuecat.org/resources/215230952334-yyno","Merchants' Bridge",1,1,"{""street"":""Benediktsplatz 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""service@erfurt-tourismus.de"",""phone"":""+49 361 66 400"",""fax"":"""",""geo"":{""latitude"":50.978772,""longitude"":11.031622}}","[]" -,8,10,2,6,6,"\NULL","https://thuecat.org/resources/215230952334-yyno","Pont de l'épicier",1,1,"{""street"":""Benediktsplatz 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""service@erfurt-tourismus.de"",""phone"":""+49 361 66 400"",""fax"":"""",""geo"":{""latitude"":50.978772,""longitude"":11.031622}}","[]" diff --git a/Tests/Functional/Fixtures/Import/ImportsSyncScope.php b/Tests/Functional/Fixtures/Import/ImportsSyncScope.php new file mode 100644 index 0000000..548bb80 --- /dev/null +++ b/Tests/Functional/Fixtures/Import/ImportsSyncScope.php @@ -0,0 +1,66 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_DEFAULT, + 'title' => 'Rootpage', + 'is_siteroot' => '1', + ], + 1 => [ + 'uid' => '10', + 'pid' => '1', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_SYSFOLDER, + 'title' => 'Storage folder', + ], + ], + 'tx_thuecat_import_configuration' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'disable' => '0', + 'title' => 'Sync Scope ID', + 'type' => 'syncScope', + 'configuration' => ' + + + + + + 10 + + + dd4615dc-58a6-4648-a7ce-4950293a06db + + + + + ', + ], + ], + 'tx_thuecat_town' => [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'tstamp' => '1613401129', + 'crdate' => '1613401129', + 'disable' => '0', + 'remote_id' => 'https://thuecat.org/resources/043064193523-jcyt', + 'managed_by' => '1', + 'tourist_information' => '0', + 'title' => 'Erfurt', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Import/ImportsSyncScope.xml b/Tests/Functional/Fixtures/Import/ImportsSyncScope.xml deleted file mode 100644 index dfc6f48..0000000 --- a/Tests/Functional/Fixtures/Import/ImportsSyncScope.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 4 - Rootpage - 1 - - - 10 - 1 - 1613400587 - 1613400558 - 1 - 254 - Storage folder - - - - 1 - 0 - English - en-us-gb - en - - - - 2 - 0 - French - fr - fr - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 0 - Sync Scope ID - syncScope - - - - - - - 10 - - - dd4615dc-58a6-4648-a7ce-4950293a06db - - - - - ]]> - - - - 1 - 10 - 1613401129 - 1613401129 - 1 - 0 - https://thuecat.org/resources/043064193523-jcyt - 1 - 0 - Erfurt - - diff --git a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithAccessibilitySpecification.csv b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithAccessibilitySpecification.csv deleted file mode 100644 index 4e41dfc..0000000 --- a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithAccessibilitySpecification.csv +++ /dev/null @@ -1,4 +0,0 @@ -"tx_thuecat_tourist_attraction",,,,,,,, -,"uid","pid","sys_language_uid","l18n_parent","l10n_source","remote_id","title" -,1,10,0,0,0,"https://thuecat.org/resources/attraction-with-accessibility-specification","Attraktion mit accessibility specification" -,2,10,1,1,1,"https://thuecat.org/resources/attraction-with-accessibility-specification","Attraction with accessibility specification" diff --git a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithAccessibilitySpecification.php b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithAccessibilitySpecification.php new file mode 100644 index 0000000..665cde5 --- /dev/null +++ b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithAccessibilitySpecification.php @@ -0,0 +1,65 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_DEFAULT, + 'title' => 'Rootpage', + 'is_siteroot' => '1', + ], + 1 => [ + 'uid' => '10', + 'pid' => '1', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_SYSFOLDER, + 'title' => 'Storage folder', + ], + ], + 'tx_thuecat_import_configuration' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'disable' => '0', + 'title' => 'Tourist Attraction', + 'type' => 'static', + 'configuration' => ' + + + + + + 10 + + + + + + + + https://thuecat.org/resources/attraction-with-accessibility-certification + + + + 0 + + + + + + + + ', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithAccessibilitySpecification.xml b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithAccessibilitySpecification.xml deleted file mode 100644 index 0754c1b..0000000 --- a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithAccessibilitySpecification.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 4 - Rootpage - 1 - - - 10 - 1 - 1613400587 - 1613400558 - 1 - 254 - Storage folder - - - - 1 - 0 - English - en-us-gb - en - - - - 2 - 0 - French - fr - fr - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 0 - Tourist Attraction - static - - - - - - - 10 - - - - - - - - https://thuecat.org/resources/attraction-with-accessibility-certification - - - - 0 - - - - - - - - ]]> - - diff --git a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithFilteredOpeningHours.php b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithFilteredOpeningHours.php new file mode 100644 index 0000000..8c251b3 --- /dev/null +++ b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithFilteredOpeningHours.php @@ -0,0 +1,65 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_DEFAULT, + 'title' => 'Rootpage', + 'is_siteroot' => '1', + ], + 1 => [ + 'uid' => '10', + 'pid' => '1', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_SYSFOLDER, + 'title' => 'Storage folder', + ], + ], + 'tx_thuecat_import_configuration' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'disable' => '0', + 'title' => 'The tourist attraction', + 'type' => 'static', + 'configuration' => ' + + + + + + 10 + + + + + + + + https://thuecat.org/resources/opening-hours-to-filter + + + + 0 + + + + + + + + ', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithFilteredOpeningHours.xml b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithFilteredOpeningHours.xml deleted file mode 100644 index 8f0ca7e..0000000 --- a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithFilteredOpeningHours.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 4 - Rootpage - 1 - - - 10 - 1 - 1613400587 - 1613400558 - 1 - 254 - Storage folder - - - - 1 - 0 - English - en-us-gb - en - - - - 2 - 0 - French - fr - fr - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 0 - The tourist attraction - static - - - - - - - 10 - - - - - - - - https://thuecat.org/resources/opening-hours-to-filter - - - - 0 - - - - - - - - ]]> - - diff --git a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithMedia.csv b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithMedia.csv deleted file mode 100644 index 7d1f60c..0000000 --- a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithMedia.csv +++ /dev/null @@ -1,4 +0,0 @@ -"tx_thuecat_tourist_attraction",,,,, -,"uid","pid","remote_id","title","media" -,1,10,"https://thuecat.org/resources/attraction-with-media","Attraktion mit Bildern","[{""mainImage"":false,""type"":""image"",""title"":""Bild mit externem Autor"",""description"":"""",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5099196\/Preview-1280x0\/image"",""author"":""GivenName FamilyName"",""copyrightYear"":0,""license"":{""type"":"""",""author"":""""}},{""mainImage"":false,""type"":""image"",""title"":""Bild mit author"",""description"":"""",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5099196\/Preview-1280x0\/image"",""author"":""Full Name"",""copyrightYear"":0,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}},{""mainImage"":false,""type"":""image"",""title"":""Bild mit license author"",""description"":"""",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5099196\/Preview-1280x0\/image"",""author"":"""",""copyrightYear"":0,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""Autor aus Lizenz""}},{""mainImage"":false,""type"":""image"",""title"":""Bild mit author und license author"",""description"":"""",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5099196\/Preview-1280x0\/image"",""author"":""Full Name"",""copyrightYear"":0,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""Autor aus Lizenz""}}]" -,2,10,"https://thuecat.org/resources/attraction-with-media","Attraction with media","[{""mainImage"":false,""type"":""image"",""title"":""Bild mit externem Autor"",""description"":"""",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5099196\/Preview-1280x0\/image"",""author"":""GivenName FamilyName"",""copyrightYear"":0,""license"":{""type"":"""",""author"":""""}},{""mainImage"":false,""type"":""image"",""title"":""Bild mit author"",""description"":"""",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5099196\/Preview-1280x0\/image"",""author"":""Full Name"",""copyrightYear"":0,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}},{""mainImage"":false,""type"":""image"",""title"":""Bild mit license author"",""description"":"""",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5099196\/Preview-1280x0\/image"",""author"":"""",""copyrightYear"":0,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""Autor aus Lizenz""}},{""mainImage"":false,""type"":""image"",""title"":""Bild mit author und license author"",""description"":"""",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5099196\/Preview-1280x0\/image"",""author"":""Full Name"",""copyrightYear"":0,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""Autor aus Lizenz""}}]" diff --git a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithMedia.php b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithMedia.php new file mode 100644 index 0000000..56dc92e --- /dev/null +++ b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithMedia.php @@ -0,0 +1,65 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_DEFAULT, + 'title' => 'Rootpage', + 'is_siteroot' => '1', + ], + 1 => [ + 'uid' => '10', + 'pid' => '1', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_SYSFOLDER, + 'title' => 'Storage folder', + ], + ], + 'tx_thuecat_import_configuration' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'disable' => '0', + 'title' => 'Tourist Attraction', + 'type' => 'static', + 'configuration' => ' + + + + + + 10 + + + + + + + + https://thuecat.org/resources/attraction-with-media + + + + 0 + + + + + + + + ', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithMedia.xml b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithMedia.xml deleted file mode 100644 index d48484f..0000000 --- a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithMedia.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 4 - Rootpage - 1 - - - 10 - 1 - 1613400587 - 1613400558 - 1 - 254 - Storage folder - - - - 1 - 0 - English - en-us-gb - en - - - - 2 - 0 - French - fr - fr - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 0 - Tourist Attraction - static - - - - - - - 10 - - - - - - - - https://thuecat.org/resources/attraction-with-media - - - - 0 - - - - - - - - ]]> - - diff --git a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithSpecialOpeningHours.php b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithSpecialOpeningHours.php new file mode 100644 index 0000000..74e887f --- /dev/null +++ b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithSpecialOpeningHours.php @@ -0,0 +1,65 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_DEFAULT, + 'title' => 'Rootpage', + 'is_siteroot' => '1', + ], + 1 => [ + 'uid' => '10', + 'pid' => '1', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_SYSFOLDER, + 'title' => 'Storage folder', + ], + ], + 'tx_thuecat_import_configuration' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'disable' => '0', + 'title' => 'The tourist attraction', + 'type' => 'static', + 'configuration' => ' + + + + + + 10 + + + + + + + + https://thuecat.org/resources/special-opening-hours + + + + 0 + + + + + + + + ', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithSpecialOpeningHours.xml b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithSpecialOpeningHours.xml deleted file mode 100644 index 50c2234..0000000 --- a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithSpecialOpeningHours.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 4 - Rootpage - 1 - - - 10 - 1 - 1613400587 - 1613400558 - 1 - 254 - Storage folder - - - - 1 - 0 - English - en-us-gb - en - - - - 2 - 0 - French - fr - fr - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 0 - The tourist attraction - static - - - - - - - 10 - - - - - - - - https://thuecat.org/resources/special-opening-hours - - - - 0 - - - - - - - - ]]> - - diff --git a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithFilteredOpeningHours.csv b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithFilteredOpeningHours.csv deleted file mode 100644 index 10e195d..0000000 --- a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithFilteredOpeningHours.csv +++ /dev/null @@ -1,4 +0,0 @@ -"tx_thuecat_tourist_attraction",,,,,,,, -,"uid","pid","sys_language_uid","l18n_parent","l10n_source","remote_id","title","opening_hours" -,1,10,0,0,0,"https://thuecat.org/resources/835224016581-dara","Dom St. Marien","[{""opens"":""13:00:00"",""closes"":""17:00:00"",""from"":{""date"":""2050-11-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2050-04-30 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Sunday""]}]" -,2,10,1,1,1,"https://thuecat.org/resources/835224016581-dara","Cathedral of St. Mary","[{""opens"":""13:00:00"",""closes"":""17:00:00"",""from"":{""date"":""2050-11-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2050-04-30 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Sunday""]}]" diff --git a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithFilteredOpeningHours.php b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithFilteredOpeningHours.php new file mode 100644 index 0000000..62d8aa2 --- /dev/null +++ b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithFilteredOpeningHours.php @@ -0,0 +1,28 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'sys_language_uid' => '0', + 'l18n_parent' => '0', + 'l10n_source' => '0', + 'remote_id' => 'https://thuecat.org/resources/835224016581-dara', + 'title' => 'Dom St. Marien', + 'opening_hours' => '[{"opens":"13:00:00","closes":"17:00:00","from":{"date":"2050-11-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2050-04-30 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Sunday"]}]', + ], + 1 => [ + 'uid' => '2', + 'pid' => '10', + 'sys_language_uid' => '1', + 'l18n_parent' => '1', + 'l10n_source' => '1', + 'remote_id' => 'https://thuecat.org/resources/835224016581-dara', + 'title' => 'Cathedral of St. Mary', + 'opening_hours' => '[{"opens":"13:00:00","closes":"17:00:00","from":{"date":"2050-11-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2050-04-30 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Sunday"]}]', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithRelations.csv b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithRelations.csv deleted file mode 100644 index 6d8057f..0000000 --- a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithRelations.csv +++ /dev/null @@ -1,35 +0,0 @@ -"tx_thuecat_tourist_attraction",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -,"uid","pid","sys_language_uid","l18n_parent","l10n_source","l10n_state","remote_id","title","description","managed_by","town","address","offers","media","slogan","start_of_construction","sanitation","other_service","museum_service","architectural_style","traffic_infrastructure","payment_accepted","digital_offer","photography","pets_allowed","is_accessible_for_free","public_access","available_languages","distance_to_public_transport","parking_facility_near_by","accessibility_specification","url" -,1,10,0,0,0,"\NULL","https://thuecat.org/resources/835224016581-dara","Dom St. Marien","Über eine 70-stufige Freitreppe gelangt man vom Domplatz auf den Domberg mit seinen beiden ehemaligen Stiftskirchen. Der Dom, mit hochgotischem Chor, romanischem Turmbereich und spätgotischer Westhalle, ist Nachfolger des 724 von Rom veranlassten Sakralbaus. Er war die Hauptkirche des 742 von Bischof Bonifatius gegründeten Bistums Erfurt und während des Mittelalters bis in das frühe 19. Jahrhundert Sitz des Collegiatstifts St. Marien. 1507 erhielt Martin Luther hier die Priesterweihe. -Der ursprünglich romanische Kirchenbau wurde in der Zeit der Gotik entscheidend umgebaut. Besonders sehenswert sind die gotischen Chorfenster, das umfängliche Chorgestühl (14. Jhd.) sowie die romanischen Skulpturen einer thronenden Madonna und eines monumentalen Kerzenträgers im Innenraum. Berühmt ist er auch wegen der „Gloriosa“, der mit 2,56 m Durchmesser größten freischwingenden mittelalterlichen Glocke der Welt. -Das Ensemble von Dom und Severikirche bildet eine imposante Kulisse für die jährlich im Sommer stattfindenden DomStufen-Festspiele.",1,1,"{""street"":""Domstufen 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""dominformation@domberg-erfurt.de"",""phone"":""+49 361 6461265"",""fax"":"""",""geo"":{""latitude"":50.975955358589545,""longitude"":11.023667024961856}}","[]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Dom und Severikirche-beleuchtet.jpg"",""description"":"""",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159216\/Preview-1280x0\/image"",""author"":"""",""copyrightYear"":2016,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Dom-und-Severikirche.jpg"",""description"":""Sicht auf Dom St. Marien, St. Severikirche sowie die davor liegenden Klostergeb\u00e4ude und einem Ausschnitt des Biergartens umgeben von einem d\u00e4mmerungsverf\u00e4rten Himmel"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159186\/Preview-1280x0\/image"",""author"":"""",""copyrightYear"":2020,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}}]",,,"Toilets,DisabledToilets","SeatingPossibilitiesRestArea,SouvenirShop",,"GothicArt","BicycleLockersEnumMem,BusParkCoachParkEnumMem",,"AugmentedReality","Fotogenehmigung für innen","false","true","true","German,English","350:MTR:Streetcar:CityBus",1,"{}","http://www.dom-erfurt.de" -,2,10,1,1,1,"\NULL","https://thuecat.org/resources/835224016581-dara","Cathedral of St. Mary","The late Gothic cathedral with its high-Gothic choir and Romanesque tower replaced the church built on this site for Bishop Boniface in 742. The central tower houses the ""Gloriosa"", the world’s largest medieval free-swinging bell.",1,1,"{""street"":""Domstufen 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""dominformation@domberg-erfurt.de"",""phone"":""+49 361 6461265"",""fax"":"""",""geo"":{""latitude"":50.975955358589545,""longitude"":11.023667024961856}}","[]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Dom und Severikirche-beleuchtet.jpg"",""description"":"""",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159216\/Preview-1280x0\/image"",""author"":"""",""copyrightYear"":2016,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Dom-und-Severikirche.jpg"",""description"":""Sicht auf Dom St. Marien, St. Severikirche sowie die davor liegenden Klostergeb\u00e4ude und einem Ausschnitt des Biergartens umgeben von einem d\u00e4mmerungsverf\u00e4rten Himmel"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159186\/Preview-1280x0\/image"",""author"":"""",""copyrightYear"":2020,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}}]",,,"Toilets,DisabledToilets","SeatingPossibilitiesRestArea,SouvenirShop",,"GothicArt","BicycleLockersEnumMem,BusParkCoachParkEnumMem",,"AugmentedReality",,"false","true","true","German,English","350:MTR:Streetcar:CityBus",1,"{}","http://www.dom-erfurt.de" -,3,10,0,0,0,"\NULL","https://thuecat.org/resources/165868194223-zmqf","Alte Synagoge","Beispiel Beschreibung",1,1,"{""street"":""Waagegasse 8"",""zip"":""99084"",""city"":""Erfurt"",""email"":""altesynagoge@erfurt.de"",""phone"":""+49 361 6551520"",""fax"":""+49 361 6551669"",""geo"":{""latitude"":50.978765,""longitude"":11.029133}}","[{""types"":[""GuidedTourOffer""],""title"":""F\u00fchrungen"",""description"":""Immer samstags, um 11:15 Uhr findet eine \u00f6ffentliche F\u00fchrung durch das Museum statt. Dauer etwa 90 Minuten"",""prices"":[{""title"":""Erwachsene"",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":""Erm\u00e4\u00dfigt"",""description"":""als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt"",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""}]},{""types"":[""EntryOffer""],""title"":""Eintritt"",""description"":""Schulklassen und Kitagruppen im Rahmen des Unterrichts: Eintritt frei\nAn jedem ersten Dienstag im Monat: Eintritt frei"",""prices"":[{""title"":""Erm\u00e4\u00dfigt"",""description"":""als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt"",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":""Familienkarte"",""description"":"""",""price"":17,""currency"":""EUR"",""rule"":""PerGroup""},{""title"":""ErfurtCard"",""description"":"""",""price"":14.9,""currency"":""EUR"",""rule"":""PerPackage""},{""title"":""Erwachsene"",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""}]}]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Alte Synagoge"",""description"":""Frontaler Blick auf die Hausfront\/Hausfassade im Innenhof mit Zugang \u00fcber die Waagegasse"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5099196\/Preview-1280x0\/image"",""author"":"""",""copyrightYear"":2009,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""F:\\Bilddatenbank\\Museen und Ausstellungen\\Alte Synagoge""}}]","Highlight","11. Jh.","Toilets,DisabledToilets,NappyChangingArea,FamilyAndChildFriendly","SeatingPossibilitiesRestArea,LockBoxes,SouvenirShop,BaggageStorage","MuseumShop","GothicArt","ZeroSpecialTrafficInfrastructure","CashPayment,EC","AudioGuide,VideoGuide","ZeroPhotography","Tiere sind im Gebäude nicht gestattet, ausgenommen sind Blinden- und Blindenbegleithunde.","false","true","German,English,French","200:MTR:CityBus",,"{""accessibilityCertificationStatus"":""AccessibilityChecked"",""certificationAccessibilityDeaf"":""None"",""certificationAccessibilityMental"":""None"",""certificationAccessibilityPartiallyDeaf"":""None"",""certificationAccessibilityPartiallyVisual"":""Info"",""certificationAccessibilityVisual"":""None"",""certificationAccessibilityWalking"":""Info"",""certificationAccessibilityWheelchair"":""Info"",""accessibilitySearchCriteria"":{""facilityAccessibilityWalking"":[""AllRoomsStepFreeAccess"",""HingedGrabRailToilet"",""LateralAccessibleToilet"",""StepFreeAccess"",""ToiletsPeopleWithDisabilities"",""NinetyCMWidthPassageWays"",""SpecialOffersWalkingImpairment"",""SpecialOffersWheelchairUsers""],""facilityAccessibilityVisual"":[""AssistanceDogsWelcome"",""VisuallyContrastingStepEdges"",""OffersInPictoralLanguage"",""SpecialOffersBlindPeople"",""SpecialOffersVisualImpairment"",""TactileOffers""],""facilityAccessibilityDeaf"":[""AudioInductionLoop"",""SpecialOffersHearingImpairment""],""facilityAccessibilityMental"":[""InformationWithPictogramsOrPictures""]},""shortDescriptionAccessibilityDeaf"":""Deutsche Beschreibung von shortDescriptionAccessibilityDeaf"",""shortDescriptionAccessibilityMental"":""Deutsche Beschreibung von shortDescriptionAccessibilityMental"",""shortDescriptionAccessibilityVisual"":""Deutsche Beschreibung von shortDescriptionAccessibilityVisual"",""shortDescriptionAccessibilityWalking"":""Deutsche Beschreibung von shortDescriptionAccessibilityWalking""}","http://www.alte-synagoge.erfurt.de" -,4,10,1,3,3,"\NULL","https://thuecat.org/resources/165868194223-zmqf","Old Synagogue","The Old Synagogue is one of very few preserved medieval synagogues in Europe. Thanks to the extensive preservation of the original structure, it has a special place in the history of art and architecture and is among the most impressive and highly rated architectural monuments in Erfurt and Thuringia. The synagogue was constructed during the Middle Ages on the ""via regia"", one of the major European trade routes, at the heart of the historical old quarter very close to the Merchants Bridge and the town hall. Many parts of the structure still remain today, including all four thick outer walls, the Roman­esque gemel window, the Gothic rose window and the entrance to the synagogue room.",1,1,"{""street"":""Waagegasse 8"",""zip"":""99084"",""city"":""Erfurt"",""email"":""altesynagoge@erfurt.de"",""phone"":""+49 361 6551520"",""fax"":""+49 361 6551669"",""geo"":{""latitude"":50.978765,""longitude"":11.029133}}","[{""types"":[""GuidedTourOffer""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":"""",""description"":"""",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""}]},{""types"":[""EntryOffer""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":"""",""description"":"""",""price"":17,""currency"":""EUR"",""rule"":""PerGroup""},{""title"":"""",""description"":"""",""price"":14.9,""currency"":""EUR"",""rule"":""PerPackage""},{""title"":"""",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""}]}]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Alte Synagoge"",""description"":""Frontaler Blick auf die Hausfront\/Hausfassade im Innenhof mit Zugang \u00fcber die Waagegasse"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5099196\/Preview-1280x0\/image"",""author"":"""",""copyrightYear"":2009,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""F:\\Bilddatenbank\\Museen und Ausstellungen\\Alte Synagoge""}}]","Highlight","11th century","Toilets,DisabledToilets,NappyChangingArea,FamilyAndChildFriendly","SeatingPossibilitiesRestArea,LockBoxes,SouvenirShop,BaggageStorage","MuseumShop","GothicArt","ZeroSpecialTrafficInfrastructure","CashPayment,EC","AudioGuide,VideoGuide","ZeroPhotography",,"false","true","German,English,French","200:MTR:CityBus",,"{""accessibilityCertificationStatus"":""AccessibilityChecked"",""certificationAccessibilityDeaf"":""None"",""certificationAccessibilityMental"":""None"",""certificationAccessibilityPartiallyDeaf"":""None"",""certificationAccessibilityPartiallyVisual"":""Info"",""certificationAccessibilityVisual"":""None"",""certificationAccessibilityWalking"":""Info"",""certificationAccessibilityWheelchair"":""Info"",""accessibilitySearchCriteria"":{""facilityAccessibilityWalking"":[""AllRoomsStepFreeAccess"",""HingedGrabRailToilet"",""LateralAccessibleToilet"",""StepFreeAccess"",""ToiletsPeopleWithDisabilities"",""NinetyCMWidthPassageWays"",""SpecialOffersWalkingImpairment"",""SpecialOffersWheelchairUsers""],""facilityAccessibilityVisual"":[""AssistanceDogsWelcome"",""VisuallyContrastingStepEdges"",""OffersInPictoralLanguage"",""SpecialOffersBlindPeople"",""SpecialOffersVisualImpairment"",""TactileOffers""],""facilityAccessibilityDeaf"":[""AudioInductionLoop"",""SpecialOffersHearingImpairment""],""facilityAccessibilityMental"":[""InformationWithPictogramsOrPictures""]},""shortDescriptionAccessibilityDeaf"":""English description of shortDescriptionAccessibilityDeaf"",""shortDescriptionAccessibilityMental"":""English description of shortDescriptionAccessibilityMental"",""shortDescriptionAccessibilityVisual"":""English description of shortDescriptionAccessibilityVisual"",""shortDescriptionAccessibilityWalking"":""English description of shortDescriptionAccessibilityWalking""}","http://www.alte-synagoge.erfurt.de" -,5,10,2,3,3,"\NULL","https://thuecat.org/resources/165868194223-zmqf","La vieille synagogue","La vieille synagogue (datant des années 1100) est la synagogue la plus vieille d’Europe totalement conservée, dans laquelle est exposé un trésor datant des 13/14èmes siècles avec une alliance juive unique et des écritures hébraïques (datant des 12ème, 13ème et 14èmes siècles). Après la redécouverte du Mikwé, Erfurt abrite des témoins uniques et fascinants d’une communauté juive médiévale.",1,1,"{""street"":""Waagegasse 8"",""zip"":""99084"",""city"":""Erfurt"",""email"":""altesynagoge@erfurt.de"",""phone"":""+49 361 6551520"",""fax"":""+49 361 6551669"",""geo"":{""latitude"":50.978765,""longitude"":11.029133}}","[{""types"":[""GuidedTourOffer""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":"""",""description"":"""",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""}]},{""types"":[""EntryOffer""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":"""",""description"":"""",""price"":17,""currency"":""EUR"",""rule"":""PerGroup""},{""title"":"""",""description"":"""",""price"":14.9,""currency"":""EUR"",""rule"":""PerPackage""},{""title"":"""",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""}]}]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Alte Synagoge"",""description"":""Frontaler Blick auf die Hausfront\/Hausfassade im Innenhof mit Zugang \u00fcber die Waagegasse"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5099196\/Preview-1280x0\/image"",""author"":"""",""copyrightYear"":2009,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""F:\\Bilddatenbank\\Museen und Ausstellungen\\Alte Synagoge""}}]","Highlight",,"Toilets,DisabledToilets,NappyChangingArea,FamilyAndChildFriendly","SeatingPossibilitiesRestArea,LockBoxes,SouvenirShop,BaggageStorage","MuseumShop","GothicArt","ZeroSpecialTrafficInfrastructure","CashPayment,EC","AudioGuide,VideoGuide","ZeroPhotography",,"false","true","German,English,French","200:MTR:CityBus",,"{""accessibilityCertificationStatus"":""AccessibilityChecked"",""certificationAccessibilityDeaf"":""None"",""certificationAccessibilityMental"":""None"",""certificationAccessibilityPartiallyDeaf"":""None"",""certificationAccessibilityPartiallyVisual"":""Info"",""certificationAccessibilityVisual"":""None"",""certificationAccessibilityWalking"":""Info"",""certificationAccessibilityWheelchair"":""Info"",""accessibilitySearchCriteria"":{""facilityAccessibilityWalking"":[""AllRoomsStepFreeAccess"",""HingedGrabRailToilet"",""LateralAccessibleToilet"",""StepFreeAccess"",""ToiletsPeopleWithDisabilities"",""NinetyCMWidthPassageWays"",""SpecialOffersWalkingImpairment"",""SpecialOffersWheelchairUsers""],""facilityAccessibilityVisual"":[""AssistanceDogsWelcome"",""VisuallyContrastingStepEdges"",""OffersInPictoralLanguage"",""SpecialOffersBlindPeople"",""SpecialOffersVisualImpairment"",""TactileOffers""],""facilityAccessibilityDeaf"":[""AudioInductionLoop"",""SpecialOffersHearingImpairment""],""facilityAccessibilityMental"":[""InformationWithPictogramsOrPictures""]}}","http://www.alte-synagoge.erfurt.de" -,6,10,0,0,0,"\NULL","https://thuecat.org/resources/215230952334-yyno","Krämerbrücke","Ein bekanntes Wahrzeichen Erfurts ist die Krämerbrücke, die längste bebaute und bewohnte Brücke Europas.Die Krämerbrücke wurde zu Beginn aus Holz und 1325 aus Stein erbaut. Zunächst war die 120 m lange Brücke mit 62 schmalen Häusern bebaut. Später wurden einige der Häuser auf nun mehr 32 zusammengefasst. An beiden Enden der Brücke standen zwei Brückenkopfkirchen. Heute existiert nur noch eine der beiden, die östlich gelegene Ägidienkirche.Auf der Krämerbrücke kann man in Galerien und Boutiquen sehr schön bummeln gehen. Man kann Thüringer Handwerksmeistern bei ihrer Arbeit über die Schulter schauen. Keramik, Porzellan und Holzschnitzereien, Blaudruck und Lauschaer Glas sind beliebte Souvenirs. Cafès, Weinhändler und Feinkostgeschäfte mit Thüringer Spezialitäten laden zum Verweilen ein.",1,1,"{""street"":""Benediktsplatz 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""service@erfurt-tourismus.de"",""phone"":""+49 361 66 400"",""fax"":"""",""geo"":{""latitude"":50.978772,""longitude"":11.031622}}","[]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Kraemerbruecke-11.jpg"",""description"":""Kr\u00e4merbr\u00fccke in Erfurt"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134362\/Preview-1280x0\/image"",""author"":""Florian Trykowski"",""copyrightYear"":2019,""license"":{""type"":""https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de"",""author"":""https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Kraemerbruecke.jpg"",""description"":""Kr\u00e4merbr\u00fccke in Erfurt"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134288\/Preview-1280x0\/image"",""author"":""Florian Trykowski"",""copyrightYear"":2019,""license"":{""type"":""https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de"",""author"":""https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Kraemerbruecke-13.jpg"",""description"":""Ansicht der Kr\u00e4merbr\u00fccke, Erfurt"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/652340\/Preview-1280x0\/image"",""author"":""Florian Trykowski"",""copyrightYear"":2019,""license"":{""type"":""https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de"",""author"":""https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion""}}]",,,"ZeroSanitation","Playground,SeatingPossibilitiesRestArea,SouvenirShop,PlayCornerOrPlayArea",,"ZeroInformationArchitecturalStyle","BicycleLockersEnumMem",,"ZeroDigitalOffer","TakingPicturesPermitted","true","true","true","German,English,French","250:MTR","1,4","{}","https://www.erfurt-tourismus.de/sehenswertes/kraemerbruecke" -,7,10,1,6,6,"\NULL","https://thuecat.org/resources/215230952334-yyno","Merchants' Bridge","Another Erfurt landmark is the Merchants' Bridge (Krämerbrücke), the longest series of inhabited buildings on any bridge in Europe. The Merchants' Bridge is Erfurts most interesting secular construction, initially in wood but rebuilt in stone in 1325. There were originally 62 narrow buildings along its 120-metre length, but subsequent redevelopment left just 32 buildings. Of what was once a pair of bridgehead churches, only the Church of St. Aegidius remains at the eastern end of the bridge today. The Merchants' Bridge is lined with galleries, cafés and boutiques offering traditional crafts, Thuringian blue printed fabrics, hand-painted ceramics, handblown glassware, jewellery, wood carvings, antiques and delicious Thuringian specialities - perfect for browsing.",1,1,"{""street"":""Benediktsplatz 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""service@erfurt-tourismus.de"",""phone"":""+49 361 66 400"",""fax"":"""",""geo"":{""latitude"":50.978772,""longitude"":11.031622}}","[]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Kraemerbruecke-11.jpg"",""description"":""Kr\u00e4merbr\u00fccke in Erfurt"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134362\/Preview-1280x0\/image"",""author"":""Florian Trykowski"",""copyrightYear"":2019,""license"":{""type"":""https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de"",""author"":""https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Kraemerbruecke.jpg"",""description"":""Kr\u00e4merbr\u00fccke in Erfurt"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134288\/Preview-1280x0\/image"",""author"":""Florian Trykowski"",""copyrightYear"":2019,""license"":{""type"":""https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de"",""author"":""https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Kraemerbruecke-13.jpg"",""description"":""Ansicht der Kr\u00e4merbr\u00fccke, Erfurt"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/652340\/Preview-1280x0\/image"",""author"":""Florian Trykowski"",""copyrightYear"":2019,""license"":{""type"":""https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de"",""author"":""https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion""}}]",,,"ZeroSanitation","Playground,SeatingPossibilitiesRestArea,SouvenirShop,PlayCornerOrPlayArea",,"ZeroInformationArchitecturalStyle","BicycleLockersEnumMem",,"ZeroDigitalOffer","TakingPicturesPermitted","true","true","true","German,English,French","250:MTR","1,4","{}","https://www.erfurt-tourismus.de/sehenswertes/kraemerbruecke" -,8,10,2,6,6,"\NULL","https://thuecat.org/resources/215230952334-yyno","Pont de l'épicier","Le pont de l’épicier est un des symboles de la ville d’Erfurt, le plus grand pont habité en continu d’Europe. A l’origine, le pont de l’épicier faisait 120 m de long et comptait 62 maisons étroites, qui furent plus tard regroupées en 32 maisons. Sur le pont de l’épicier se trouvent des galeries et des petites échoppes proposant des étoffes à motifs bleu indigo de Thuringe, des céramiques peintes main, du verre de Lauscha, des bijoux et des sculptures en bois.",1,1,"{""street"":""Benediktsplatz 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""service@erfurt-tourismus.de"",""phone"":""+49 361 66 400"",""fax"":"""",""geo"":{""latitude"":50.978772,""longitude"":11.031622}}","[]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Kraemerbruecke-11.jpg"",""description"":""Kr\u00e4merbr\u00fccke in Erfurt"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134362\/Preview-1280x0\/image"",""author"":""Florian Trykowski"",""copyrightYear"":2019,""license"":{""type"":""https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de"",""author"":""https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Kraemerbruecke.jpg"",""description"":""Kr\u00e4merbr\u00fccke in Erfurt"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134288\/Preview-1280x0\/image"",""author"":""Florian Trykowski"",""copyrightYear"":2019,""license"":{""type"":""https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de"",""author"":""https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Kraemerbruecke-13.jpg"",""description"":""Ansicht der Kr\u00e4merbr\u00fccke, Erfurt"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/652340\/Preview-1280x0\/image"",""author"":""Florian Trykowski"",""copyrightYear"":2019,""license"":{""type"":""https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de"",""author"":""https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion""}}]",,,"ZeroSanitation","Playground,SeatingPossibilitiesRestArea,SouvenirShop,PlayCornerOrPlayArea",,"ZeroInformationArchitecturalStyle","BicycleLockersEnumMem",,"ZeroDigitalOffer","TakingPicturesPermitted","true","true","true","German,English,French","250:MTR","1,4","{}","https://www.erfurt-tourismus.de/sehenswertes/kraemerbruecke" -"tx_thuecat_parking_facility",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -,"uid","pid","sys_language_uid","l18n_parent","l10n_source","l10n_state","remote_id","title","description","managed_by","address","offers","media","sanitation","other_service","traffic_infrastructure","payment_accepted","distance_to_public_transport",,,,,,,,,,,,,, -,1,10,0,0,0,"\NULL","https://thuecat.org/resources/396420044896-drzt","Parkhaus Domplatz","Das Parkhaus Domplatz befindet sich unmittelbar unterhalb der Zitadelle Petersberg am nördlichen Rand des Domplatzes. Durch die zentrale Lage ist es ein idealer Ausgangspunkt für Stadtbummel und Erkundungen des Zentrums, des Petersbergs und des Andreasviertels.",1,"{""street"":""Bechtheimer Str. 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""info@stadtwerke-erfurt.de"",""phone"":""+49 361 5640"",""fax"":"""",""geo"":{""latitude"":50.977648905044,""longitude"":11.022127985954299}}","[{""types"":[""ParkingFee""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":35,""currency"":""EUR"",""rule"":""PerCar""}]},{""types"":[""ParkingFee""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":1.5,""currency"":""EUR"",""rule"":""PerCar""}]},{""types"":[""ParkingFee""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":10,""currency"":""EUR"",""rule"":""PerCar""}]},{""types"":[""ParkingFee""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":50,""currency"":""EUR"",""rule"":""PerCar""}]}]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Parkhaus-Domplatz.jpg"",""description"":"""",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/6486108\/Preview-1280x0\/image"",""author"":""Florian Trykowski"",""copyrightYear"":2021,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}}]","ZeroSanitation","ZeroOtherServiceEnumMem","ElectricVehicleCarChargingStationEnumMem",,"240:MTR:CityBus",,,,,,,,,,,,,, -,2,10,1,1,1,"\NULL","https://thuecat.org/resources/396420044896-drzt","Car park Domplatz","The Domplatz multi-storey car park is located directly below the Petersberg Citadel on the northern edge of the Domplatz. Its central location makes it an ideal starting point for strolling through the city and exploring the centre, the Petersberg and the Andreasviertel.",1,"{""street"":""Bechtheimer Str. 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""info@stadtwerke-erfurt.de"",""phone"":""+49 361 5640"",""fax"":"""",""geo"":{""latitude"":50.977648905044,""longitude"":11.022127985954299}}","[{""types"":[""ParkingFee""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":35,""currency"":""EUR"",""rule"":""PerCar""}]},{""types"":[""ParkingFee""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":1.5,""currency"":""EUR"",""rule"":""PerCar""}]},{""types"":[""ParkingFee""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":10,""currency"":""EUR"",""rule"":""PerCar""}]},{""types"":[""ParkingFee""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":50,""currency"":""EUR"",""rule"":""PerCar""}]}]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Parkhaus-Domplatz.jpg"",""description"":"""",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/6486108\/Preview-1280x0\/image"",""author"":""Florian Trykowski"",""copyrightYear"":2021,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}}]","ZeroSanitation","ZeroOtherServiceEnumMem","ElectricVehicleCarChargingStationEnumMem",,"240:MTR:CityBus",,,,,,,,,,,,,, -,3,10,2,1,1,"\NULL","https://thuecat.org/resources/396420044896-drzt","Parking Domplatz","Le parking à étages de la Domplatz est situé juste en dessous de la citadelle de Petersberg, sur le bord nord de la Domplatz. Son emplacement central en fait un point de départ idéal pour se promener dans la ville et explorer le centre, le Petersberg et l'Andreasviertel.",1,"{""street"":""Bechtheimer Str. 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""info@stadtwerke-erfurt.de"",""phone"":""+49 361 5640"",""fax"":"""",""geo"":{""latitude"":50.977648905044,""longitude"":11.022127985954299}}","[{""types"":[""ParkingFee""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":35,""currency"":""EUR"",""rule"":""PerCar""}]},{""types"":[""ParkingFee""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":1.5,""currency"":""EUR"",""rule"":""PerCar""}]},{""types"":[""ParkingFee""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":10,""currency"":""EUR"",""rule"":""PerCar""}]},{""types"":[""ParkingFee""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":50,""currency"":""EUR"",""rule"":""PerCar""}]}]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Parkhaus-Domplatz.jpg"",""description"":"""",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/6486108\/Preview-1280x0\/image"",""author"":""Florian Trykowski"",""copyrightYear"":2021,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}}]","ZeroSanitation","ZeroOtherServiceEnumMem","ElectricVehicleCarChargingStationEnumMem",,"240:MTR:CityBus",,,,,,,,,,,,,, -,4,10,0,0,0,"\NULL","https://thuecat.org/resources/440055527204-ocar","Q-Park Anger 1 Parkhaus","Der Q-Park liegt direkt hinter dem Kaufhaus Anger 1 im Erfurter Stadtzentrum und ist über Juri-Gagarin-Ring/Meyfartstraße zu erreichen. Durch die direkte Anbindung an den Stadtring, ist das Parkhaus gut von außerhalb über Schnellstraßen und Autobahnen zu erreichen und befindet sich gleichzeitig im unmittelbaren modernen Zentrum Erfurts.",1,"{""street"":""Anger 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""servicecenter@q-park.de"",""phone"":""+49 218 18190290"",""fax"":"""",""geo"":{""latitude"":50.977999330565794,""longitude"":11.037503264052475}}","[{""types"":[""ParkingFee""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":2.2,""currency"":""EUR"",""rule"":""PerCar""}]},{""types"":[""ParkingFee""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":1,""currency"":""EUR"",""rule"":""PerCar""}]},{""types"":[""ParkingFee""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":13,""currency"":""EUR"",""rule"":""PerCar""}]}]","[{""mainImage"":true,""type"":""image"",""title"":""Q-Park-Parkhaus-Anger1-Juri-Gagarin-Ring.JPG"",""description"":""Stra\u00dfenansicht des Parkhauses Q-Park am Kaufhaus Anger 1, schr\u00e4g \u00fcber den Juri-Gagarin-Ring"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5197164\/Preview-1280x0\/image"",""author"":""Florian Trykowski"",""copyrightYear"":2020,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}}]","Toilets","ZeroOtherServiceEnumMem",,,"120:MTR",,,,,,,,,,,,,, -,5,10,1,4,4,"\NULL","https://thuecat.org/resources/440055527204-ocar","Q-Park Anger 1 multi-storey car park","The Q-Park is located directly behind the department store Anger 1 in Erfurt's city centre and can be reached via Juri-Gagarin-Ring/Meyfartstraße.",1,"{""street"":""Anger 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""servicecenter@q-park.de"",""phone"":""+49 218 18190290"",""fax"":"""",""geo"":{""latitude"":50.977999330565794,""longitude"":11.037503264052475}}","[{""types"":[""ParkingFee""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":2.2,""currency"":""EUR"",""rule"":""PerCar""}]},{""types"":[""ParkingFee""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":1,""currency"":""EUR"",""rule"":""PerCar""}]},{""types"":[""ParkingFee""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":13,""currency"":""EUR"",""rule"":""PerCar""}]}]","[{""mainImage"":true,""type"":""image"",""title"":""Q-Park-Parkhaus-Anger1-Juri-Gagarin-Ring.JPG"",""description"":""Stra\u00dfenansicht des Parkhauses Q-Park am Kaufhaus Anger 1, schr\u00e4g \u00fcber den Juri-Gagarin-Ring"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5197164\/Preview-1280x0\/image"",""author"":""Florian Trykowski"",""copyrightYear"":2020,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}}]","Toilets","ZeroOtherServiceEnumMem",,,"120:MTR",,,,,,,,,,,,,, -,6,10,2,4,4,"\NULL","https://thuecat.org/resources/440055527204-ocar","Q-Park Anger 1 parking à étages","Le Q-Park est situé directement derrière le grand magasin Anger 1 dans le centre-ville d'Erfurt et peut être atteint par la Juri-Gagarin-Ring/Meyfartstraße.",1,"{""street"":""Anger 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""servicecenter@q-park.de"",""phone"":""+49 218 18190290"",""fax"":"""",""geo"":{""latitude"":50.977999330565794,""longitude"":11.037503264052475}}","[{""types"":[""ParkingFee""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":2.2,""currency"":""EUR"",""rule"":""PerCar""}]},{""types"":[""ParkingFee""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":1,""currency"":""EUR"",""rule"":""PerCar""}]},{""types"":[""ParkingFee""],""title"":"""",""description"":"""",""prices"":[{""title"":"""",""description"":"""",""price"":13,""currency"":""EUR"",""rule"":""PerCar""}]}]","[{""mainImage"":true,""type"":""image"",""title"":""Q-Park-Parkhaus-Anger1-Juri-Gagarin-Ring.JPG"",""description"":""Stra\u00dfenansicht des Parkhauses Q-Park am Kaufhaus Anger 1, schr\u00e4g \u00fcber den Juri-Gagarin-Ring"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5197164\/Preview-1280x0\/image"",""author"":""Florian Trykowski"",""copyrightYear"":2020,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}}]","Toilets","ZeroOtherServiceEnumMem",,,"120:MTR",,,,,,,,,,,,,, -"tx_thuecat_organisation",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -,"uid","pid","remote_id","title","description",,,,,,,,,,,,,,,,,,,,,,,,,,, -,1,10,"https://thuecat.org/resources/018132452787-ngbe","Erfurt Tourismus und Marketing GmbH","Die Erfurt Tourismus & Marketing GmbH (ETMG) wurde 1997 als offizielle Organisation zur Tourismusförderung in der Landeshauptstadt Erfurt gegründet und nahm am 01.01.1998 die Geschäftstätigkeit auf. - -Zu den Aufgaben zählen die kommunale Tourismusförderung als wesentliches Instrument der Wirtschafts- und Stadtentwicklung der Landeshauptstadt Erfurt, die Positionierung der Stadt Erfurt auf dem nationalen und internationalen Tourismusmarkt als dynamische und sympathische Landeshauptstadt, attraktives Städtereiseziel und Tagungsstandort, die Vervollkommnung des touristischen Serviceangebotes entsprechend den Bedürfnissen der individuellen Gäste und der Tourismuswirtschaft und das Betreiben der Erfurt Tourist Information. - -Im Januar 2009 wurde das Marketing für die Landeshauptstadt Erfurt an die ETMG übertragen und neu geordnet. Die Hauptaufgaben im Stadtmarketing liegen darin, die Wahrnehmung der Stadt in folgenden Bereichen zu verstärken: traditionsreicher und innovativer Wirtschaftsstandort, lebendiger und kreativer Wissenschaftsstandort, attraktiver Wohnstandort mit Flair und Sportstandort mit exzellenten Bedingungen für Nachwuchs- und Spitzensportler. - -Gesellschafter: Stadt Erfurt - -Geschäftsführerin: Frau Dr. Carmen Hildebrandt - -Aufsichtsratsvorsitzender: Herr Dominik Kordon - -Mitarbeiter: ca. 30 Angestellte, 4 Auszubildende",,,,,,,,,,,,,,,,,,,,,,,,,,, diff --git a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithRelations.xml b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithRelations.php similarity index 58% rename from Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithRelations.xml rename to Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithRelations.php index 7a7fecb..2a149f8 100644 --- a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithRelations.xml +++ b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithRelations.php @@ -1,51 +1,39 @@ - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 4 - Rootpage - 1 - - - 10 - 1 - 1613400587 - 1613400558 - 1 - 254 - Storage folder - + - 1 - 0 - English - en-us-gb - en - +declare(strict_types=1); - - 2 - 0 - French - fr - fr - +use TYPO3\CMS\Core\Domain\Repository\PageRepository; - - 1 - 0 - 1613400587 - 1613400558 - 1 - 0 - Three tourist attractions - static - +return [ + 'pages' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_DEFAULT, + 'title' => 'Rootpage', + 'is_siteroot' => '1', + ], + 1 => [ + 'uid' => '10', + 'pid' => '1', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_SYSFOLDER, + 'title' => 'Storage folder', + ], + ], + 'tx_thuecat_import_configuration' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'disable' => '0', + 'title' => 'Three tourist attractions', + 'type' => 'static', + 'configuration' => ' @@ -91,19 +79,20 @@ - ]]> - - - - 1 - 10 - 1613401129 - 1613401129 - 1 - 0 - https://thuecat.org/resources/043064193523-jcyt - 1 - 0 - Erfurt - - + ', + ], + ], + 'tx_thuecat_town' => [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'tstamp' => '1613401129', + 'crdate' => '1613401129', + 'disable' => '0', + 'remote_id' => 'https://thuecat.org/resources/043064193523-jcyt', + 'managed_by' => '1', + 'tourist_information' => '0', + 'title' => 'Erfurt', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithSpecialOpeningHours.csv b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithSpecialOpeningHours.csv deleted file mode 100644 index 8e2b176..0000000 --- a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithSpecialOpeningHours.csv +++ /dev/null @@ -1,4 +0,0 @@ -"tx_thuecat_tourist_attraction",,,,,,,, -,"uid","pid","sys_language_uid","l18n_parent","l10n_source","remote_id","title","special_opening_hours" -,1,10,0,0,0,"https://thuecat.org/resources/835224016581-dara","Dom St. Marien","[{""opens"":""10:00:00"",""closes"":""14:00:00"",""from"":{""date"":""2050-12-31 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2050-12-31 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Saturday""]}]" -,2,10,1,1,1,"https://thuecat.org/resources/835224016581-dara","Cathedral of St. Mary","[{""opens"":""10:00:00"",""closes"":""14:00:00"",""from"":{""date"":""2050-12-31 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2050-12-31 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Saturday""]}]" diff --git a/Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithSpecialOpeningHours.php b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithSpecialOpeningHours.php new file mode 100644 index 0000000..3be421f --- /dev/null +++ b/Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithSpecialOpeningHours.php @@ -0,0 +1,28 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'sys_language_uid' => '0', + 'l18n_parent' => '0', + 'l10n_source' => '0', + 'remote_id' => 'https://thuecat.org/resources/835224016581-dara', + 'title' => 'Dom St. Marien', + 'special_opening_hours' => '[{"opens":"10:00:00","closes":"14:00:00","from":{"date":"2050-12-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2050-12-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Saturday"]}]', + ], + 1 => [ + 'uid' => '2', + 'pid' => '10', + 'sys_language_uid' => '1', + 'l18n_parent' => '1', + 'l10n_source' => '1', + 'remote_id' => 'https://thuecat.org/resources/835224016581-dara', + 'title' => 'Cathedral of St. Mary', + 'special_opening_hours' => '[{"opens":"10:00:00","closes":"14:00:00","from":{"date":"2050-12-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2050-12-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Saturday"]}]', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Import/ImportsTouristInformationWithRelation.csv b/Tests/Functional/Fixtures/Import/ImportsTouristInformationWithRelation.csv deleted file mode 100644 index 8e13dd4..0000000 --- a/Tests/Functional/Fixtures/Import/ImportsTouristInformationWithRelation.csv +++ /dev/null @@ -1,9 +0,0 @@ -"tx_thuecat_tourist_information",,,,,,, -,"uid","pid","remote_id","title","description","managed_by","town" -,1,10,"https://thuecat.org/resources/333039283321-xxwg","Erfurt Tourist Information","Direkt an der Krämerbrücke liegt die Erfurter Tourist Information. Nach einer Modernisierung im Frühjahr 2017 erstrahlt diese in neuem Glanz und ist auch technisch auf dem neuesten Stand. Hier erhalten Sie Stadtpläne, Broschüren zu Erfurt und originelle Souvenirs. Zudem bietet die Tourist Information vielfältige Stadtführungen und Rundfahrten mit Straßenbahn oder Bus sowie kompetente Beratung zu Hotels, Pensionen und Privatunterkünften.",1,1 -"tx_thuecat_town",,,,,,, -,"uid","pid","remote_id","title","description","managed_by", -,1,10,"https://thuecat.org/resources/043064193523-jcyt","Erfurt","Krämerbrücke, Dom, Alte Synagoge – die Thüringer Landeshauptstadt Erfurt hat viele Kulturschätze. Und ein wunderbar junges, studentisches Flair.Eine gute Mischung für alle, die beim Schlendern und Bummeln gerne Städte entdecken: Denn in Erfurt findet man einen wunderbaren mittelalterlichen Stadtkern – mit vielen netten Läden, Cafès und Restaurants. Urlauber wie Einheimische bummeln durch die Gassen der Altstadt, aus allen Ecken wispern Geschichte und alte Geschichten. Stolze historische Bügerhäuser bilden eine der schönsten Altstädte Europas, mittendrin das neugotische Rathaus aus den 1870er-Jahren am Fischmarkt, die spitztürmige St. Severikirche und der mächtige Dom, 1117 erstmals urkundlich erwähnt – auf seiner schier endlosen, kaskadenförmigen Freitreppe chillen Jung und Alt gern in der Abendsonne. Ehe sie weiter ziehen zum Tagesausklang in eine der coolen Kneipen und Bars (Tipp: Oma Lilo oder Cafè Hilgenfeld), in die Wein-Destille am benachbarten Petersberg oder in eins der lässigen Restaurants (Tipp: Mathilda oder Ballenberger), wo zum freundlichen Miteinander eine frische und moderne Küche serviert wird.In Erfurt pulsiert das Leben, lassen Sie sich einfach treiben. Von Ihrer Neugierde ...",1, -"tx_thuecat_organisation",,,,,,, -,"uid","pid","remote_id","title",,, -,1,10,"https://thuecat.org/resources/018132452787-ngbe","Erfurt Tourismus und Marketing GmbH",,, diff --git a/Tests/Functional/Fixtures/Import/ImportsTouristInformationWithRelation.php b/Tests/Functional/Fixtures/Import/ImportsTouristInformationWithRelation.php new file mode 100644 index 0000000..5c30d9b --- /dev/null +++ b/Tests/Functional/Fixtures/Import/ImportsTouristInformationWithRelation.php @@ -0,0 +1,65 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_DEFAULT, + 'title' => 'Rootpage', + 'is_siteroot' => '1', + ], + 1 => [ + 'uid' => '10', + 'pid' => '1', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_SYSFOLDER, + 'title' => 'Storage folder', + ], + ], + 'tx_thuecat_import_configuration' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'disable' => '0', + 'title' => 'Tourist Information', + 'type' => 'static', + 'configuration' => ' + + + + + + 10 + + + + + + + + https://thuecat.org/resources/333039283321-xxwg + + + + 0 + + + + + + + + ', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Import/ImportsTouristInformationWithRelation.xml b/Tests/Functional/Fixtures/Import/ImportsTouristInformationWithRelation.xml deleted file mode 100644 index 853f080..0000000 --- a/Tests/Functional/Fixtures/Import/ImportsTouristInformationWithRelation.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 4 - Rootpage - 1 - - - 10 - 1 - 1613400587 - 1613400558 - 1 - 254 - Storage folder - - - - 1 - 0 - English - en-us-gb - en - - - - 2 - 0 - French - fr - fr - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 0 - Tourist Information - static - - - - - - - 10 - - - - - - - - https://thuecat.org/resources/333039283321-xxwg - - - - 0 - - - - - - - - ]]> - - diff --git a/Tests/Functional/Fixtures/Import/ImportsTown.csv b/Tests/Functional/Fixtures/Import/ImportsTown.csv deleted file mode 100644 index ad43804..0000000 --- a/Tests/Functional/Fixtures/Import/ImportsTown.csv +++ /dev/null @@ -1,6 +0,0 @@ -"tx_thuecat_town",,,,,, -,"uid","pid","remote_id","title","description","managed_by" -,1,10,"https://thuecat.org/resources/043064193523-jcyt","Erfurt","Krämerbrücke, Dom, Alte Synagoge – die Thüringer Landeshauptstadt Erfurt hat viele Kulturschätze. Und ein wunderbar junges, studentisches Flair.Eine gute Mischung für alle, die beim Schlendern und Bummeln gerne Städte entdecken: Denn in Erfurt findet man einen wunderbaren mittelalterlichen Stadtkern – mit vielen netten Läden, Cafès und Restaurants. Urlauber wie Einheimische bummeln durch die Gassen der Altstadt, aus allen Ecken wispern Geschichte und alte Geschichten. Stolze historische Bügerhäuser bilden eine der schönsten Altstädte Europas, mittendrin das neugotische Rathaus aus den 1870er-Jahren am Fischmarkt, die spitztürmige St. Severikirche und der mächtige Dom, 1117 erstmals urkundlich erwähnt – auf seiner schier endlosen, kaskadenförmigen Freitreppe chillen Jung und Alt gern in der Abendsonne. Ehe sie weiter ziehen zum Tagesausklang in eine der coolen Kneipen und Bars (Tipp: Oma Lilo oder Cafè Hilgenfeld), in die Wein-Destille am benachbarten Petersberg oder in eins der lässigen Restaurants (Tipp: Mathilda oder Ballenberger), wo zum freundlichen Miteinander eine frische und moderne Küche serviert wird.In Erfurt pulsiert das Leben, lassen Sie sich einfach treiben. Von Ihrer Neugierde ...",1 -"tx_thuecat_organisation",,,,,, -,"uid","pid","remote_id","title",, -,1,10,"https://thuecat.org/resources/018132452787-ngbe","Erfurt Tourismus und Marketing GmbH",, diff --git a/Tests/Functional/Fixtures/Import/ImportsTown.php b/Tests/Functional/Fixtures/Import/ImportsTown.php new file mode 100644 index 0000000..0c36017 --- /dev/null +++ b/Tests/Functional/Fixtures/Import/ImportsTown.php @@ -0,0 +1,65 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_DEFAULT, + 'title' => 'Rootpage', + 'is_siteroot' => '1', + ], + 1 => [ + 'uid' => '10', + 'pid' => '1', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_SYSFOLDER, + 'title' => 'Storage folder', + ], + ], + 'tx_thuecat_import_configuration' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'disable' => '0', + 'title' => 'Town', + 'type' => 'static', + 'configuration' => ' + + + + + + 10 + + + + + + + + https://thuecat.org/resources/043064193523-jcyt + + + + 0 + + + + + + + + ', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Import/ImportsTown.xml b/Tests/Functional/Fixtures/Import/ImportsTown.xml deleted file mode 100644 index 42a0445..0000000 --- a/Tests/Functional/Fixtures/Import/ImportsTown.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 4 - Rootpage - 1 - - - 10 - 1 - 1613400587 - 1613400558 - 1 - 254 - Storage folder - - - - 1 - 0 - English - en-us-gb - en - - - - 2 - 0 - French - fr - fr - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 0 - Town - static - - - - - - - 10 - - - - - - - - https://thuecat.org/resources/043064193523-jcyt - - - - 0 - - - - - - - - ]]> - - diff --git a/Tests/Functional/Fixtures/Import/ImportsTownWithRelation.csv b/Tests/Functional/Fixtures/Import/ImportsTownWithRelation.csv deleted file mode 100644 index ad43804..0000000 --- a/Tests/Functional/Fixtures/Import/ImportsTownWithRelation.csv +++ /dev/null @@ -1,6 +0,0 @@ -"tx_thuecat_town",,,,,, -,"uid","pid","remote_id","title","description","managed_by" -,1,10,"https://thuecat.org/resources/043064193523-jcyt","Erfurt","Krämerbrücke, Dom, Alte Synagoge – die Thüringer Landeshauptstadt Erfurt hat viele Kulturschätze. Und ein wunderbar junges, studentisches Flair.Eine gute Mischung für alle, die beim Schlendern und Bummeln gerne Städte entdecken: Denn in Erfurt findet man einen wunderbaren mittelalterlichen Stadtkern – mit vielen netten Läden, Cafès und Restaurants. Urlauber wie Einheimische bummeln durch die Gassen der Altstadt, aus allen Ecken wispern Geschichte und alte Geschichten. Stolze historische Bügerhäuser bilden eine der schönsten Altstädte Europas, mittendrin das neugotische Rathaus aus den 1870er-Jahren am Fischmarkt, die spitztürmige St. Severikirche und der mächtige Dom, 1117 erstmals urkundlich erwähnt – auf seiner schier endlosen, kaskadenförmigen Freitreppe chillen Jung und Alt gern in der Abendsonne. Ehe sie weiter ziehen zum Tagesausklang in eine der coolen Kneipen und Bars (Tipp: Oma Lilo oder Cafè Hilgenfeld), in die Wein-Destille am benachbarten Petersberg oder in eins der lässigen Restaurants (Tipp: Mathilda oder Ballenberger), wo zum freundlichen Miteinander eine frische und moderne Küche serviert wird.In Erfurt pulsiert das Leben, lassen Sie sich einfach treiben. Von Ihrer Neugierde ...",1 -"tx_thuecat_organisation",,,,,, -,"uid","pid","remote_id","title",, -,1,10,"https://thuecat.org/resources/018132452787-ngbe","Erfurt Tourismus und Marketing GmbH",, diff --git a/Tests/Functional/Fixtures/Import/ImportsTownWithRelation.php b/Tests/Functional/Fixtures/Import/ImportsTownWithRelation.php new file mode 100644 index 0000000..9c277ca --- /dev/null +++ b/Tests/Functional/Fixtures/Import/ImportsTownWithRelation.php @@ -0,0 +1,76 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_DEFAULT, + 'title' => 'Rootpage', + 'is_siteroot' => '1', + ], + 1 => [ + 'uid' => '10', + 'pid' => '1', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_SYSFOLDER, + 'title' => 'Storage folder', + ], + ], + 'tx_thuecat_import_configuration' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'disable' => '0', + 'title' => 'Town', + 'type' => 'static', + 'configuration' => ' + + + + + + 10 + + + + + + + + https://thuecat.org/resources/043064193523-jcyt + + + + 0 + + + + + + + + ', + ], + ], + 'tx_thuecat_organisation' => [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'disable' => '0', + 'remote_id' => 'https://thuecat.org/resources/018132452787-ngbe', + 'title' => 'Old title', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Import/ImportsTownWithRelation.xml b/Tests/Functional/Fixtures/Import/ImportsTownWithRelation.xml deleted file mode 100644 index 1920bf9..0000000 --- a/Tests/Functional/Fixtures/Import/ImportsTownWithRelation.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 4 - Rootpage - 1 - - - 10 - 1 - 1613400587 - 1613400558 - 1 - 254 - Storage folder - - - - 1 - 0 - English - en-us-gb - en - - - - 2 - 0 - French - fr - fr - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 0 - Town - static - - - - - - - 10 - - - - - - - - https://thuecat.org/resources/043064193523-jcyt - - - - 0 - - - - - - - - ]]> - - - - 1 - 10 - 1613400587 - 1613400558 - 1 - 0 - https://thuecat.org/resources/018132452787-ngbe - Old title - - diff --git a/Tests/Functional/Fixtures/Import/UpdatesExistingOrganization.php b/Tests/Functional/Fixtures/Import/UpdatesExistingOrganization.php new file mode 100644 index 0000000..4cc81eb --- /dev/null +++ b/Tests/Functional/Fixtures/Import/UpdatesExistingOrganization.php @@ -0,0 +1,76 @@ + [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_DEFAULT, + 'title' => 'Rootpage', + 'is_siteroot' => '1', + ], + 1 => [ + 'uid' => '10', + 'pid' => '1', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'doktype' => PageRepository::DOKTYPE_SYSFOLDER, + 'title' => 'Storage folder', + ], + ], + 'tx_thuecat_import_configuration' => [ + 0 => [ + 'uid' => '1', + 'pid' => '0', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'disable' => '0', + 'title' => 'Single Fresh Organisation', + 'type' => 'static', + 'configuration' => ' + + + + + + 10 + + + + + + + + https://thuecat.org/resources/018132452787-ngbe + + + + 0 + + + + + + + + ', + ], + ], + 'tx_thuecat_organisation' => [ + 0 => [ + 'uid' => '1', + 'pid' => '10', + 'tstamp' => '1613400587', + 'crdate' => '1613400558', + 'disable' => '0', + 'remote_id' => 'https://thuecat.org/resources/018132452787-ngbe', + 'title' => 'Old title', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Import/UpdatesExistingOrganization.xml b/Tests/Functional/Fixtures/Import/UpdatesExistingOrganization.xml deleted file mode 100644 index fb46747..0000000 --- a/Tests/Functional/Fixtures/Import/UpdatesExistingOrganization.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 4 - Rootpage - 1 - - - 10 - 1 - 1613400587 - 1613400558 - 1 - 254 - Storage folder - - - - 1 - 0 - 1613400587 - 1613400558 - 1 - 0 - Single Fresh Organisation - static - - - - - - - 10 - - - - - - - - https://thuecat.org/resources/018132452787-ngbe - - - - 0 - - - - - - - - ]]> - - - - 1 - 10 - 1613400587 - 1613400558 - 1 - 0 - https://thuecat.org/resources/018132452787-ngbe - Old title - - diff --git a/Tests/Functional/FrontendTest.php b/Tests/Functional/FrontendTest.php index 4d204f4..7848a6a 100644 --- a/Tests/Functional/FrontendTest.php +++ b/Tests/Functional/FrontendTest.php @@ -23,11 +23,16 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Tests\Functional; +use Codappix\Typo3PhpDatasets\TestingFramework; +use DateTimeImmutable; +use PHPUnit\Framework\Attributes\Test; use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequest; use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase; class FrontendTest extends FunctionalTestCase { + use TestingFramework; + protected function setUp(): void { $this->coreExtensionsToLoad = [ @@ -35,7 +40,7 @@ class FrontendTest extends FunctionalTestCase ]; $this->testExtensionsToLoad = [ - 'typo3conf/ext/thuecat/', + 'werkraummedia/thuecat', ]; $this->pathsToLinkInTestInstance = [ @@ -44,7 +49,7 @@ class FrontendTest extends FunctionalTestCase parent::setUp(); - $this->importDataSet('EXT:thuecat/Tests/Functional/Fixtures/Frontend/Content.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Frontend/Content.php'); $this->setUpFrontendRootPage(1, [ 'EXT:fluid_styled_content/Configuration/TypoScript/setup.typoscript', 'EXT:thuecat/Configuration/TypoScript/ContentElements/setup.typoscript', @@ -52,17 +57,15 @@ class FrontendTest extends FunctionalTestCase ]); } - /** - * @test - */ + #[Test] public function touristAttractionContentElementIsRendered(): void { - $this->importDataSet('EXT:thuecat/Tests/Functional/Fixtures/Frontend/TouristAttractions.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Frontend/TouristAttractions.php'); $request = new InternalRequest(); $request = $request->withPageId(2); - $result = $this->executeFrontendRequest($request); + $result = $this->executeFrontendSubRequest($request); self::assertSame(200, $result->getStatusCode()); @@ -252,13 +255,11 @@ class FrontendTest extends FunctionalTestCase self::assertStringContainsString('WC für Menschen mit Behinderung', (string)$result->getBody()); } - /** - * @test - */ + #[Test] public function touristAttractionContentElementRespectsEditorialSorting(): void { - $this->importDataSet('EXT:thuecat/Tests/Functional/Fixtures/Frontend/TouristAttractions.xml'); - $this->importDataSet('EXT:thuecat/Tests/Functional/Fixtures/Frontend/SecondTouristAttraction.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Frontend/TouristAttractions.php'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Frontend/SecondTouristAttraction.php'); $this->getConnectionPool()->getConnectionForTable('tt_content')->update( 'tt_content', @@ -271,7 +272,7 @@ class FrontendTest extends FunctionalTestCase $request = new InternalRequest(); $request = $request->withPageId(2); - $html = (string)$this->executeFrontendRequest($request)->getBody(); + $html = (string)$this->executeFrontendSubRequest($request)->getBody(); self::assertGreaterThan( stripos($html, 'Eine weitere Attraktion'), @@ -279,119 +280,105 @@ class FrontendTest extends FunctionalTestCase ); } - /** - * @test - */ + #[Test] public function touristAttractionWithPetsFalse(): void { - $this->importDataSet('EXT:thuecat/Tests/Functional/Fixtures/Frontend/TouristAttractionsForPets.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Frontend/TouristAttractionsForPets.php'); $request = new InternalRequest(); $request = $request->withPageId(4); - $result = $this->executeFrontendRequest($request); + $result = $this->executeFrontendSubRequest($request); self::assertSame(200, $result->getStatusCode()); self::assertStringContainsString('Keine Tiere erlaubt', (string)$result->getBody()); } - /** - * @test - */ + #[Test] public function touristAttractionWithPetsTrue(): void { - $this->importDataSet('EXT:thuecat/Tests/Functional/Fixtures/Frontend/TouristAttractionsForPets.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Frontend/TouristAttractionsForPets.php'); $request = new InternalRequest(); $request = $request->withPageId(5); - $result = $this->executeFrontendRequest($request); + $result = $this->executeFrontendSubRequest($request); self::assertSame(200, $result->getStatusCode()); self::assertStringContainsString('Tiere erlaubt', (string)$result->getBody()); } - /** - * @test - */ + #[Test] public function touristAttractionWithIsAccessibleForFreeFalse(): void { - $this->importDataSet('EXT:thuecat/Tests/Functional/Fixtures/Frontend/TouristAttractionsForIsAccessibleForFree.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Frontend/TouristAttractionsForIsAccessibleForFree.php'); $request = new InternalRequest(); $request = $request->withPageId(4); - $result = $this->executeFrontendRequest($request); + $result = $this->executeFrontendSubRequest($request); self::assertSame(200, $result->getStatusCode()); self::assertStringContainsString('kein freier Eintritt', (string)$result->getBody()); } - /** - * @test - */ + #[Test] public function touristAttractionWithIsAccessibleForFreeTrue(): void { - $this->importDataSet('EXT:thuecat/Tests/Functional/Fixtures/Frontend/TouristAttractionsForIsAccessibleForFree.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Frontend/TouristAttractionsForIsAccessibleForFree.php'); $request = new InternalRequest(); $request = $request->withPageId(5); - $result = $this->executeFrontendRequest($request); + $result = $this->executeFrontendSubRequest($request); self::assertSame(200, $result->getStatusCode()); self::assertStringContainsString('freier Eintritt', (string)$result->getBody()); } - /** - * @test - */ + #[Test] public function touristAttractionWithPublicAccessFalse(): void { - $this->importDataSet('EXT:thuecat/Tests/Functional/Fixtures/Frontend/TouristAttractionsForPublicAccess.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Frontend/TouristAttractionsForPublicAccess.php'); $request = new InternalRequest(); $request = $request->withPageId(4); - $result = $this->executeFrontendRequest($request); + $result = $this->executeFrontendSubRequest($request); self::assertSame(200, $result->getStatusCode()); self::assertStringContainsString('nicht öffentlich zugänglich', (string)$result->getBody()); } - /** - * @test - */ + #[Test] public function touristAttractionWithPublicAccessTrue(): void { - $this->importDataSet('EXT:thuecat/Tests/Functional/Fixtures/Frontend/TouristAttractionsForPublicAccess.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Frontend/TouristAttractionsForPublicAccess.php'); $request = new InternalRequest(); $request = $request->withPageId(5); - $result = $this->executeFrontendRequest($request); + $result = $this->executeFrontendSubRequest($request); self::assertSame(200, $result->getStatusCode()); self::assertStringContainsString('öffentlich zugänglich', (string)$result->getBody()); } - /** - * @test - */ + #[Test] public function pricesAreSorted(): void { - $this->importDataSet('EXT:thuecat/Tests/Functional/Fixtures/Frontend/TouristAttractionWithPrices.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Frontend/TouristAttractionWithPrices.php'); $request = new InternalRequest(); $request = $request->withPageId(2); - $result = $this->executeFrontendRequest($request); + $result = $this->executeFrontendSubRequest($request); self::assertSame(200, $result->getStatusCode()); @@ -414,17 +401,15 @@ class FrontendTest extends FunctionalTestCase ); } - /** - * @test - */ + #[Test] public function offersAreSortedByType(): void { - $this->importDataSet('EXT:thuecat/Tests/Functional/Fixtures/Frontend/TouristAttractionWithOfferTypes.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Frontend/TouristAttractionWithOfferTypes.php'); $request = new InternalRequest(); $request = $request->withPageId(2); - $result = $this->executeFrontendRequest($request); + $result = $this->executeFrontendSubRequest($request); self::assertSame(200, $result->getStatusCode()); @@ -452,15 +437,13 @@ class FrontendTest extends FunctionalTestCase ); } - /** - * @test - */ + #[Test] public function openingHoursAreFilteredByThough(): void { - $this->importDataSet('EXT:thuecat/Tests/Functional/Fixtures/Frontend/TouristAttractionsOpeningHours.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Frontend/TouristAttractionsOpeningHours.php'); - $hidden = new \DateTimeImmutable('yesterday'); - $available = new \DateTimeImmutable('tomorrow'); + $hidden = new DateTimeImmutable('yesterday'); + $available = new DateTimeImmutable('tomorrow'); $this->getConnectionPool() ->getConnectionForTable('tx_thuecat_tourist_attraction') @@ -499,12 +482,13 @@ class FrontendTest extends FunctionalTestCase ], ])], ['uid' => 1] - ); + ) + ; $request = new InternalRequest(); $request = $request->withPageId(2); - $result = (string)$this->executeFrontendRequest($request)->getBody(); + $result = (string)$this->executeFrontendSubRequest($request)->getBody(); self::assertStringNotContainsString('14:00', $result); self::assertStringNotContainsString('13:00', $result); @@ -519,16 +503,14 @@ class FrontendTest extends FunctionalTestCase self::assertStringContainsString($available->format('d.m.Y'), $result); } - /** - * @test - */ + #[Test] public function openingHoursAreSortedByFrom(): void { - $this->importDataSet('EXT:thuecat/Tests/Functional/Fixtures/Frontend/TouristAttractionsOpeningHours.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Frontend/TouristAttractionsOpeningHours.php'); - $fromFirstOpening = new \DateTimeImmutable('today'); - $fromSecondOpening = new \DateTimeImmutable('+2 days'); - $fromThirdOpening = new \DateTimeImmutable('+7 days'); + $fromFirstOpening = new DateTimeImmutable('today'); + $fromSecondOpening = new DateTimeImmutable('+2 days'); + $fromThirdOpening = new DateTimeImmutable('+7 days'); $this->getConnectionPool() ->getConnectionForTable('tx_thuecat_tourist_attraction') @@ -582,12 +564,13 @@ class FrontendTest extends FunctionalTestCase ], ])], ['uid' => 1] - ); + ) + ; $request = new InternalRequest(); $request = $request->withPageId(2); - $result = (string)$this->executeFrontendRequest($request)->getBody(); + $result = (string)$this->executeFrontendSubRequest($request)->getBody(); $positionFirstHour = mb_strpos($result, $fromFirstOpening->format('d.m.Y')); $positionSecondHour = mb_strpos($result, $fromSecondOpening->format('d.m.Y')); @@ -597,16 +580,14 @@ class FrontendTest extends FunctionalTestCase self::assertLessThan($positionSecondHour, $positionFirstHour, 'Second hour does not come after first hour.'); } - /** - * @test - */ + #[Test] public function specialOpeningHoursAreRendered(): void { - $this->importDataSet('EXT:thuecat/Tests/Functional/Fixtures/Frontend/TouristAttractionsOpeningHours.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Frontend/TouristAttractionsOpeningHours.php'); - $hidden = new \DateTimeImmutable('yesterday'); - $available = new \DateTimeImmutable('tomorrow'); - $available2 = new \DateTimeImmutable('+3 days'); + $hidden = new DateTimeImmutable('yesterday'); + $available = new DateTimeImmutable('tomorrow'); + $available2 = new DateTimeImmutable('+3 days'); $this->getConnectionPool() ->getConnectionForTable('tx_thuecat_tourist_attraction') @@ -660,12 +641,13 @@ class FrontendTest extends FunctionalTestCase ], ])], ['uid' => 1] - ); + ) + ; $request = new InternalRequest(); $request = $request->withPageId(2); - $result = (string)$this->executeFrontendRequest($request)->getBody(); + $result = (string)$this->executeFrontendSubRequest($request)->getBody(); self::assertStringNotContainsString('11:00', $result); self::assertStringNotContainsString('12:00', $result); @@ -691,17 +673,15 @@ class FrontendTest extends FunctionalTestCase self::assertLessThan($positionSecondHour, $positionFirstHour, 'Second hour does not come after first hour.'); } - /** - * @test - */ + #[Test] public function editorialImagesOfTouristAttractionAreRenderedForDefaultLanguage(): void { - $this->importDataSet('EXT:thuecat/Tests/Functional/Fixtures/Frontend/TouristAttractionWithEditorialImages.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Frontend/TouristAttractionWithEditorialImages.php'); $request = new InternalRequest(); $request = $request->withPageId(2); - $html = (string)$this->executeFrontendRequest($request)->getBody(); + $html = (string)$this->executeFrontendSubRequest($request)->getBody(); self::assertStringContainsString( '', diff --git a/Tests/Functional/GuzzleClientFaker.php b/Tests/Functional/GuzzleClientFaker.php index 27295b6..1a0d01b 100644 --- a/Tests/Functional/GuzzleClientFaker.php +++ b/Tests/Functional/GuzzleClientFaker.php @@ -4,16 +4,14 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Tests\Functional; +use Exception; use GuzzleHttp\Handler\MockHandler; use GuzzleHttp\Psr7\Response; use Symfony\Component\HttpFoundation\Response as SymfonyResponse; class GuzzleClientFaker { - /** - * @var MockHandler - */ - private static $mockHandler; + private static ?MockHandler $mockHandler = null; public static function registerClient(): void { @@ -21,7 +19,6 @@ class GuzzleClientFaker $GLOBALS['TYPO3_CONF_VARS']['HTTP']['handler']['faker'] = function (callable $handler) { return self::getMockHandler(); }; - } /** @@ -40,7 +37,7 @@ class GuzzleClientFaker { $fileContent = file_get_contents($fileName); if ($fileContent === false) { - throw new \Exception('Could not load file: ' . $fileName, 1656485162); + throw new Exception('Could not load file: ' . $fileName, 1656485162); } self::appendResponseFromContent($fileContent); diff --git a/Tests/Functional/Import/EntityMapping/BaseInfosTest.php b/Tests/Functional/Import/EntityMapping/BaseInfosTest.php index e9d46d8..c46ef5f 100644 --- a/Tests/Functional/Import/EntityMapping/BaseInfosTest.php +++ b/Tests/Functional/Import/EntityMapping/BaseInfosTest.php @@ -23,23 +23,16 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Tests\Functional\Import\EntityMapping; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; -use WerkraumMedia\ThueCat\Domain\Import\EntityMapper; -use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\JsonDecode; use WerkraumMedia\ThueCat\Domain\Import\Entity\Base; use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\ForeignReference; +use WerkraumMedia\ThueCat\Domain\Import\EntityMapper; +use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\JsonDecode; - -/** - * @covers \WerkraumMedia\ThueCat\Domain\Import\Converter\ObjectMapping - * @covers \WerkraumMedia\ThueCat\Domain\Import\Entity\Base - * @covers \WerkraumMedia\ThueCat\Domain\Import\Entity\Properies\ForeignReference - */ class BaseInfosTest extends TestCase { - /** - * @test - */ + #[Test] public function instanceOfBaseIsReturnedIfRequestes(): void { $subject = new EntityMapper(); @@ -52,9 +45,7 @@ class BaseInfosTest extends TestCase self::assertInstanceOf(Base::class, $result); } - /** - * @test - */ + #[Test] public function returnsDefaultValuesIfNotProvidedForMapping(): void { $subject = new EntityMapper(); @@ -74,9 +65,7 @@ class BaseInfosTest extends TestCase self::assertNull($result->getManagedBy()); } - /** - * @test - */ + #[Test] public function mapsIncomingDataToProperties(): void { $subject = new EntityMapper(); @@ -97,9 +86,7 @@ class BaseInfosTest extends TestCase self::assertSame(['https://example.com/the-thing'], $result->getUrls()); } - /** - * @test - */ + #[Test] public function mapsIncomingPhoto(): void { $subject = new EntityMapper(); @@ -117,9 +104,7 @@ class BaseInfosTest extends TestCase self::assertSame('https://thuecat.org/resources/835224016581-dara', $result->getPhoto()->getId()); } - /** - * @test - */ + #[Test] public function mapsIncomingImages(): void { $subject = new EntityMapper(); @@ -146,9 +131,7 @@ class BaseInfosTest extends TestCase self::assertSame('https://thuecat.org/resources/835224016581-2nd', $result->getImages()[1]->getId()); } - /** - * @test - */ + #[Test] public function mapsIncomingManagedBy(): void { $subject = new EntityMapper(); diff --git a/Tests/Functional/Import/EntityMapping/JsonDecodingTest.php b/Tests/Functional/Import/EntityMapping/JsonDecodingTest.php index 3fead38..1feb744 100644 --- a/Tests/Functional/Import/EntityMapping/JsonDecodingTest.php +++ b/Tests/Functional/Import/EntityMapping/JsonDecodingTest.php @@ -23,17 +23,13 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Tests\Functional\Import\EntityMapping; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\JsonDecode; -/** - * @covers \WerkraumMedia\ThueCat\Domain\Import\EntityMapper\JsonDecode; - */ class JsonDecodingTest extends TestCase { - /** - * @test - */ + #[Test] public function canBeCreated(): void { $subject = new JsonDecode(); @@ -44,13 +40,11 @@ class JsonDecodingTest extends TestCase ); } - /** - * @test - */ + #[Test] public function decodesPropertyWithMultipleLanguagesProvidingActiveOne(): void { $subject = new JsonDecode(); - $result = $subject->decode((string) json_encode([ + $result = $subject->decode((string)json_encode([ 'schema:name' => [ [ '@language' => 'de', @@ -70,13 +64,11 @@ class JsonDecodingTest extends TestCase ], $result); } - /** - * @test - */ + #[Test] public function decodesPropertyWithSingleLanguageMatchingActive(): void { $subject = new JsonDecode(); - $result = $subject->decode((string) json_encode([ + $result = $subject->decode((string)json_encode([ 'schema:name' => [ '@language' => 'en', '@value' => 'English Text', @@ -90,13 +82,11 @@ class JsonDecodingTest extends TestCase ], $result); } - /** - * @test - */ + #[Test] public function decodesPropertyWithSingleLanguageNotMatchingActive(): void { $subject = new JsonDecode(); - $result = $subject->decode((string) json_encode([ + $result = $subject->decode((string)json_encode([ 'schema:name' => [ '@language' => 'de', '@value' => 'German Text', @@ -110,13 +100,11 @@ class JsonDecodingTest extends TestCase ], $result); } - /** - * @test - */ + #[Test] public function decodesPropertyWithMultipleLanguagesAndFormatsProvidingActiveLanguage(): void { $subject = new JsonDecode(); - $result = $subject->decode((string) json_encode([ + $result = $subject->decode((string)json_encode([ 'schema:description' => [ 0 => [ '@language' => 'en', @@ -156,13 +144,11 @@ class JsonDecodingTest extends TestCase ], $result); } - /** - * @test - */ + #[Test] public function decodesPropertyWithMultipleLanguagesNotMatchingRequestOne(): void { $subject = new JsonDecode(); - $result = $subject->decode((string) json_encode([ + $result = $subject->decode((string)json_encode([ 'schema:description' => [ 0 => [ '@language' => 'en', @@ -182,13 +168,11 @@ class JsonDecodingTest extends TestCase ], $result); } - /** - * @test - */ + #[Test] public function decodesSingleValueNotRelatedToLanguage(): void { $subject = new JsonDecode(); - $result = $subject->decode((string) json_encode([ + $result = $subject->decode((string)json_encode([ 'schema:geo' => [ 'schema:latitude' => [ '@type' => 'schema:Number', @@ -211,13 +195,11 @@ class JsonDecodingTest extends TestCase ], $result); } - /** - * @test - */ + #[Test] public function decodesNestedObjectStructures(): void { $subject = new JsonDecode(); - $result = $subject->decode((string) json_encode([ + $result = $subject->decode((string)json_encode([ '@id' => 'https://thuecat.org/resources/835224016581-dara', 'schema:name' => [ '@language' => 'en', @@ -261,13 +243,11 @@ class JsonDecodingTest extends TestCase ], $result); } - /** - * @test - */ + #[Test] public function decodesOpeningHours(): void { $subject = new JsonDecode(); - $result = $subject->decode((string) json_encode([ + $result = $subject->decode((string)json_encode([ 'schema:openingHoursSpecification' => [ 0 => [ '@id' => 'genid-7bb7d92bd6624bdf84634c86e8acdbb4-b4', @@ -371,13 +351,11 @@ class JsonDecodingTest extends TestCase ], $result); } - /** - * @test - */ + #[Test] public function keepsArrayOfValueAndTypeIfConfigured(): void { $subject = new JsonDecode(); - $result = $subject->decode((string) json_encode([ + $result = $subject->decode((string)json_encode([ 'thuecat:AccessibilitySearchCriteria' => [ 0 => [ '@type' => 'thuecat:facilityAccessibilityWalking', diff --git a/Tests/Functional/Import/EntityMapping/PlaceInfosTest.php b/Tests/Functional/Import/EntityMapping/PlaceInfosTest.php index 654d4ff..1b6f77b 100644 --- a/Tests/Functional/Import/EntityMapping/PlaceInfosTest.php +++ b/Tests/Functional/Import/EntityMapping/PlaceInfosTest.php @@ -21,25 +21,18 @@ declare(strict_types=1); * 02110-1301, USA. */ -namespace WerkraumMedia\ThueCat\Tests\Functional\ObjectMapping; +namespace WerkraumMedia\ThueCat\Tests\Functional\Import\EntityMapping; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; -use WerkraumMedia\ThueCat\Domain\Import\EntityMapper; -use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\JsonDecode; use WerkraumMedia\ThueCat\Domain\Import\Entity\Place; use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\Address; +use WerkraumMedia\ThueCat\Domain\Import\EntityMapper; +use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\JsonDecode; -/** - * @covers \WerkraumMedia\ThueCat\Domain\Import\EntityMapper - * @covers \WerkraumMedia\ThueCat\Domain\Import\EntityMapper\JsonDecode - * @uses \WerkraumMedia\ThueCat\Domain\Import\Entity\Place - * @uses \WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\Address - */ class PlaceInfosTest extends TestCase { - /** - * @test - */ + #[Test] public function instanceOfPlaceIsReturnedIfRequestes(): void { $subject = new EntityMapper(); @@ -52,9 +45,7 @@ class PlaceInfosTest extends TestCase self::assertInstanceOf(Place::class, $result); } - /** - * @test - */ + #[Test] public function returnsDefaultValuesIfNotProvidedForMapping(): void { $subject = new EntityMapper(); @@ -68,9 +59,7 @@ class PlaceInfosTest extends TestCase self::assertSame([], $result->getOpeningHoursSpecification()); } - /** - * @test - */ + #[Test] public function mapsIncomingAddress(): void { $subject = new EntityMapper(); @@ -136,9 +125,7 @@ class PlaceInfosTest extends TestCase self::assertSame('dominformation@domberg-erfurt.de', $result->getAddress()->getEmail()); } - /** - * @test - */ + #[Test] public function mapsIncomingMultipleUrls(): void { $subject = new EntityMapper(); @@ -165,9 +152,7 @@ class PlaceInfosTest extends TestCase ], $result->getUrls()); } - /** - * @test - */ + #[Test] public function mapsIncomingSingleUrl(): void { $subject = new EntityMapper(); diff --git a/Tests/Functional/ImportConfigurationCommandTest.php b/Tests/Functional/ImportConfigurationCommandTest.php index eb5e1e5..5289f2b 100644 --- a/Tests/Functional/ImportConfigurationCommandTest.php +++ b/Tests/Functional/ImportConfigurationCommandTest.php @@ -24,37 +24,30 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Tests\Functional; use Exception; +use PHPUnit\Framework\Attributes\Test; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Exception\RuntimeException; use Symfony\Component\Console\Tester\CommandTester; use WerkraumMedia\ThueCat\Command\ImportConfigurationCommand; -/** - * @covers \WerkraumMedia\ThueCat\Command\ImportConfigurationCommand - * @testdox The 'thuecat:importviaconfiguration' command - */ -final class ImportConfigurationCommandTest extends AbstractImportTest +final class ImportConfigurationCommandTest extends AbstractImportTestCase { - /** - * @test - */ + #[Test] public function canImport(): void { $subject = $this->getContainer()->get(ImportConfigurationCommand::class); self::assertInstanceOf(Command::class, $subject); - $this->importDataSet(__DIR__ . '/Fixtures/Import/ImportsFreshOrganization.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Import/ImportsFreshOrganization.php'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/018132452787-ngbe.json'); $tester = new CommandTester($subject); $tester->execute(['configuration' => 1], ['capture_stderr_separately' => true]); - $this->assertCSVDataSet('EXT:thuecat/Tests/Functional/Fixtures/Import/ImportsFreshOrganization.csv'); + $this->assertPHPDataSet(__DIR__ . '/Assertions/Import/ImportsFreshOrganization.php'); } - /** - * @test - */ + #[Test] public function throwsExceptionOnNoneExistingConfiguration(): void { $subject = $this->getContainer()->get(ImportConfigurationCommand::class); @@ -69,9 +62,7 @@ final class ImportConfigurationCommandTest extends AbstractImportTest $tester->execute(['configuration' => 1], ['capture_stderr_separately' => true]); } - /** - * @test - */ + #[Test] public function throwsExceptionOnMissingArgument(): void { $subject = $this->getContainer()->get(ImportConfigurationCommand::class); @@ -86,9 +77,7 @@ final class ImportConfigurationCommandTest extends AbstractImportTest $tester->execute([], ['capture_stderr_separately' => true]); } - /** - * @test - */ + #[Test] public function throwsExceptionOnNoneNumericConfigurationArgument(): void { $subject = $this->getContainer()->get(ImportConfigurationCommand::class); diff --git a/Tests/Functional/ImportTest.php b/Tests/Functional/ImportTest.php index 2a570f2..a30e2fe 100644 --- a/Tests/Functional/ImportTest.php +++ b/Tests/Functional/ImportTest.php @@ -23,66 +23,31 @@ namespace WerkraumMedia\ThueCat\Tests\Functional; * 02110-1301, USA. */ +use PHPUnit\Framework\Attributes\Test; +use WerkraumMedia\ThueCat\Domain\Import\ImportConfiguration; use WerkraumMedia\ThueCat\Domain\Import\Importer; use WerkraumMedia\ThueCat\Domain\Repository\Backend\ImportConfigurationRepository; -/** - * @covers \WerkraumMedia\ThueCat\DependencyInjection\ConverterPass - * @covers \WerkraumMedia\ThueCat\DependencyInjection\UrlProvidersPass - * @covers \WerkraumMedia\ThueCat\Domain\Import\Importer\SaveData - * @covers \WerkraumMedia\ThueCat\Domain\Repository\Backend\ImportLogRepository - * @covers \WerkraumMedia\ThueCat\Domain\Repository\Backend\OrganisationRepository - * @covers \WerkraumMedia\ThueCat\Domain\Repository\Backend\TownRepository - * @covers \WerkraumMedia\ThueCat\Extension - * @covers \WerkraumMedia\ThueCat\Typo3Wrapper\TranslationService - * - * @uses \WerkraumMedia\ThueCat\Domain\Import\Converter\Organisation - * @uses \WerkraumMedia\ThueCat\Domain\Import\Converter\Registry - * @uses \WerkraumMedia\ThueCat\Domain\Import\Converter\TouristAttraction - * @uses \WerkraumMedia\ThueCat\Domain\Import\Converter\TouristInformation - * @uses \WerkraumMedia\ThueCat\Domain\Import\Converter\Town - * @uses \WerkraumMedia\ThueCat\Domain\Import\Importer - * @uses \WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData - * @uses \WerkraumMedia\ThueCat\Domain\Import\Importer\LanguageHandling - * @uses \WerkraumMedia\ThueCat\Domain\Import\Model\EntityCollection - * @uses \WerkraumMedia\ThueCat\Domain\Import\Model\GenericEntity - * @uses \WerkraumMedia\ThueCat\Domain\Import\RequestFactory - * @uses \WerkraumMedia\ThueCat\Domain\Import\UrlProvider\Registry - * @uses \WerkraumMedia\ThueCat\Domain\Import\UrlProvider\StaticUrlProvider - * @uses \WerkraumMedia\ThueCat\Domain\Import\UrlProvider\SyncScopeUrlProvider - * @uses \WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration - * @uses \WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLog - * @uses \WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLogEntry - * @uses \WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLogEntry - * - * @testdox The import - */ -class ImportTest extends AbstractImportTest +class ImportTest extends AbstractImportTestCase { - /** - * @test - */ + #[Test] public function importsFreshOrganization(): void { - $this->importDataSet(__DIR__ . '/Fixtures/Import/ImportsFreshOrganization.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Import/ImportsFreshOrganization.php'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/018132452787-ngbe.json'); - $configuration = $this->get(ImportConfigurationRepository::class)->findByUid(1); - $this->get(Importer::class)->importConfiguration($configuration); + $this->importConfiguration(); - $this->assertCSVDataSet('EXT:thuecat/Tests/Functional/Fixtures/Import/ImportsFreshOrganization.csv'); + $this->assertPHPDataSet(__DIR__ . '/Assertions/Import/ImportsFreshOrganization.php'); } - /** - * @test - */ + #[Test] public function updatesExistingOrganization(): void { - $this->importDataSet(__DIR__ . '/Fixtures/Import/UpdatesExistingOrganization.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Import/UpdatesExistingOrganization.php'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/018132452787-ngbe.json'); - $configuration = $this->get(ImportConfigurationRepository::class)->findByUid(1); - $this->get(Importer::class)->importConfiguration($configuration); + $this->importConfiguration(); $organisations = $this->getAllRecords('tx_thuecat_organisation'); self::assertCount(1, $organisations); @@ -104,45 +69,37 @@ class ImportTest extends AbstractImportTest self::assertSame('[]', $importLogEntries[0]['errors']); } - /** - * @test - */ + #[Test] public function importsTown(): void { - $this->importDataSet(__DIR__ . '/Fixtures/Import/ImportsTown.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Import/ImportsTown.php'); // TODO: Check why we request both twice. GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/043064193523-jcyt.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/018132452787-ngbe.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/043064193523-jcyt.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/018132452787-ngbe.json'); - $configuration = $this->get(ImportConfigurationRepository::class)->findByUid(1); - $this->get(Importer::class)->importConfiguration($configuration); + $this->importConfiguration(); - $this->assertCSVDataSet('EXT:thuecat/Tests/Functional/Fixtures/Import/ImportsTown.csv'); + $this->assertPHPDataSet(__DIR__ . '/Assertions/Import/ImportsTown.php'); } - /** - * @test - */ + #[Test] public function importsTownWithRelation(): void { - $this->importDataSet(__DIR__ . '/Fixtures/Import/ImportsTownWithRelation.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Import/ImportsTownWithRelation.php'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/043064193523-jcyt.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/018132452787-ngbe.json'); - $configuration = $this->get(ImportConfigurationRepository::class)->findByUid(1); - $this->get(Importer::class)->importConfiguration($configuration); + $this->importConfiguration(); - $this->assertCSVDataSet('EXT:thuecat/Tests/Functional/Fixtures/Import/ImportsTownWithRelation.csv'); + $this->assertPHPDataSet(__DIR__ . '/Assertions/Import/ImportsTownWithRelation.php'); } - /** - * @test - */ + #[Test] public function importsTouristAttractionsWithRelations(): void { - $this->importDataSet(__DIR__ . '/Fixtures/Import/ImportsTouristAttractionsWithRelations.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Import/ImportsTouristAttractionsWithRelations.php'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/835224016581-dara.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/018132452787-ngbe.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/043064193523-jcyt.json'); @@ -166,66 +123,54 @@ class ImportTest extends AbstractImportTest GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/440055527204-ocar.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/dms_5197164.json'); - $configuration = $this->get(ImportConfigurationRepository::class)->findByUid(1); - $this->get(Importer::class)->importConfiguration($configuration); + $this->importConfiguration(); - $this->assertCSVDataSet('EXT:thuecat/Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithRelations.csv'); + $this->assertPHPDataSet(__DIR__ . '/Assertions/Import/ImportsTouristAttractionsWithRelations.php'); } - /** - * @test - */ + #[Test] public function importsTouristAttractionsWithFilteredOpeningHours(): void { - $this->importDataSet(__DIR__ . '/Fixtures/Import/ImportsTouristAttractionWithFilteredOpeningHours.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Import/ImportsTouristAttractionWithFilteredOpeningHours.php'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/opening-hours-to-filter.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/018132452787-ngbe.json'); - $configuration = $this->get(ImportConfigurationRepository::class)->findByUid(1); - $this->get(Importer::class)->importConfiguration($configuration); + $this->importConfiguration(); - $this->assertCSVDataSet('EXT:thuecat/Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithFilteredOpeningHours.csv'); + $this->assertPHPDataSet(__DIR__ . '/Assertions/Import/ImportsTouristAttractionsWithFilteredOpeningHours.php'); } - /** - * @test - */ + #[Test] public function importsTouristAttractionsWithSpecialOpeningHours(): void { - $this->importDataSet(__DIR__ . '/Fixtures/Import/ImportsTouristAttractionWithSpecialOpeningHours.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Import/ImportsTouristAttractionWithSpecialOpeningHours.php'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/special-opening-hours.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/018132452787-ngbe.json'); - $configuration = $this->get(ImportConfigurationRepository::class)->findByUid(1); - $this->get(Importer::class)->importConfiguration($configuration); + $this->importConfiguration(); - $this->assertCSVDataSet('EXT:thuecat/Tests/Functional/Fixtures/Import/ImportsTouristAttractionsWithSpecialOpeningHours.csv'); + $this->assertPHPDataSet(__DIR__ . '/Assertions/Import/ImportsTouristAttractionsWithSpecialOpeningHours.php'); } - /** - * @test - */ + #[Test] public function importsTouristInformationWithRelation(): void { - $this->importDataSet(__DIR__ . '/Fixtures/Import/ImportsTouristInformationWithRelation.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Import/ImportsTouristInformationWithRelation.php'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/333039283321-xxwg.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/018132452787-ngbe.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/043064193523-jcyt.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/573211638937-gmqb.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/356133173991-cryw.json'); - $configuration = $this->get(ImportConfigurationRepository::class)->findByUid(1); - $this->get(Importer::class)->importConfiguration($configuration); + $this->importConfiguration(); - $this->assertCSVDataSet('EXT:thuecat/Tests/Functional/Fixtures/Import/ImportsTouristInformationWithRelation.csv'); + $this->assertPHPDataSet(__DIR__ . '/Assertions/Import/ImportsTouristInformationWithRelation.php'); } - /** - * @test - */ + #[Test] public function importsBasedOnSyncScope(): void { - $this->importDataSet(__DIR__ . '/Fixtures/Import/ImportsSyncScope.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Import/ImportsSyncScope.php'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/cdb.thuecat.org/api/ext-sync/get-updated-nodes/dd4615dc-58a6-4648-a7ce-4950293a06db.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/835224016581-dara.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/018132452787-ngbe.json'); @@ -250,18 +195,15 @@ class ImportTest extends AbstractImportTest GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/440055527204-ocar.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/dms_5197164.json'); - $configuration = $this->get(ImportConfigurationRepository::class)->findByUid(1); - $this->get(Importer::class)->importConfiguration($configuration); + $this->importConfiguration(); - $this->assertCSVDataSet('EXT:thuecat/Tests/Functional/Fixtures/Import/ImportsSyncScope.csv'); + $this->assertPHPDataSet(__DIR__ . '/Assertions/Import/ImportsSyncScope.php'); } - /** - * @test - */ + #[Test] public function importsBasedOnContainsPlace(): void { - $this->importDataSet(__DIR__ . '/Fixtures/Import/ImportsContainsPlace.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Import/ImportsContainsPlace.php'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/043064193523-contains.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/835224016581-dara.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/018132452787-ngbe.json'); @@ -294,19 +236,16 @@ class ImportTest extends AbstractImportTest GuzzleClientFaker::appendNotFoundResponse(); } - $configuration = $this->get(ImportConfigurationRepository::class)->findByUid(1); - $this->get(Importer::class)->importConfiguration($configuration); + $this->importConfiguration(); - $this->assertCSVDataSet('EXT:thuecat/Tests/Functional/Fixtures/Import/ImportsContainsPlace.csv'); + $this->assertPHPDataSet(__DIR__ . '/Assertions/Import/ImportsContainsPlace.php'); } - /** - * @test - */ + #[Test] public function importsFollowingRecordsInCaseOfAnMappingException(): void { $this->expectErrors = true; - $this->importDataSet(__DIR__ . '/Fixtures/Import/ImportsFollowingRecordsInCaseOfAnMappingException.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Import/ImportsFollowingRecordsInCaseOfAnMappingException.php'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/mapping-exception.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/165868194223-zmqf.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/018132452787-ngbe.json'); @@ -317,23 +256,19 @@ class ImportTest extends AbstractImportTest GuzzleClientFaker::appendNotFoundResponse(); } - $configuration = $this->get(ImportConfigurationRepository::class)->findByUid(1); - $this->get(Importer::class)->importConfiguration($configuration); + $this->importConfiguration(); if (version_compare(PHP_VERSION, '8.1.0', '<')) { - $this->assertCSVDataSet('EXT:thuecat/Tests/Functional/Fixtures/Import/ImportsFollowingRecordsInCaseOfAnMappingExceptionOldPhp.csv'); + $this->assertPHPDataSet(__DIR__ . '/Assertions/Import/ImportsFollowingRecordsInCaseOfAnMappingExceptionOldPhp.php'); } else { - $this->assertCSVDataSet('EXT:thuecat/Tests/Functional/Fixtures/Import/ImportsFollowingRecordsInCaseOfAnMappingException.csv'); + $this->assertPHPDataSet(__DIR__ . '/Assertions/Import/ImportsFollowingRecordsInCaseOfAnMappingException.php'); } } - /** - * @test - * @testdox Referencing the same thing multiple times only adds it once. - */ + #[Test] public function importWithMultipleReferencesToSameObject(): void { - $this->importDataSet(__DIR__ . '/Fixtures/Import/ImportWithMultipleReferencesToSameObject.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Import/ImportWithMultipleReferencesToSameObject.php'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/835224016581-dara.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/018132452787-ngbe.json'); @@ -358,18 +293,15 @@ class ImportTest extends AbstractImportTest GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/440055527204-ocar.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/dms_5197164.json'); - $configuration = $this->get(ImportConfigurationRepository::class)->findByUid(1); - $this->get(Importer::class)->importConfiguration($configuration); + $this->importConfiguration(); - $this->assertCSVDataSet('EXT:thuecat/Tests/Functional/Fixtures/Import/ImportWithMultipleReferencesToSameObject.csv'); + $this->assertPHPDataSet(__DIR__ . '/Assertions/Import/ImportWithMultipleReferencesToSameObject.php'); } - /** - * @test - */ + #[Test] public function importsTouristAttractionWithMedia(): void { - $this->importDataSet(__DIR__ . '/Fixtures/Import/ImportsTouristAttractionWithMedia.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Import/ImportsTouristAttractionWithMedia.php'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/attraction-with-media.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/018132452787-ngbe.json'); @@ -379,29 +311,32 @@ class ImportTest extends AbstractImportTest GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/image-with-license-author.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/image-with-author-and-license-author.json'); - $configuration = $this->get(ImportConfigurationRepository::class)->findByUid(1); - $this->get(Importer::class)->importConfiguration($configuration); + $this->importConfiguration(); - $this->assertCSVDataSet('EXT:thuecat/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithMedia.csv'); + $this->assertPHPDataSet(__DIR__ . '/Assertions/Import/ImportsTouristAttractionWithMedia.php'); } - /** - * @test - */ + #[Test] public function importsTouristAttractionWithAccessibilitySpecification(): void { - $this->importDataSet(__DIR__ . '/Fixtures/Import/ImportsTouristAttractionWithAccessibilitySpecification.xml'); + $this->importPHPDataSet(__DIR__ . '/Fixtures/Import/ImportsTouristAttractionWithAccessibilitySpecification.php'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/attraction-with-accessibility-specification.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/018132452787-ngbe.json'); GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/e_331baf4eeda4453db920dde62f7e6edc-rfa-accessibility-specification.json'); - $configuration = $this->get(ImportConfigurationRepository::class)->findByUid(1); - $this->get(Importer::class)->importConfiguration($configuration); + $this->importConfiguration(); - $this->assertCSVDataSet('EXT:thuecat/Tests/Functional/Fixtures/Import/ImportsTouristAttractionWithAccessibilitySpecification.csv'); + $this->assertPHPDataSet(__DIR__ . '/Assertions/Import/ImportsTouristAttractionWithAccessibilitySpecification.php'); $records = $this->getAllRecords('tx_thuecat_tourist_attraction'); self::assertStringEqualsFile(__DIR__ . '/Fixtures/Import/ImportsTouristAttractionWithAccessibilitySpecificationGerman.txt', $records[0]['accessibility_specification'] . PHP_EOL); self::assertStringEqualsFile(__DIR__ . '/Fixtures/Import/ImportsTouristAttractionWithAccessibilitySpecificationEnglish.txt', $records[1]['accessibility_specification'] . PHP_EOL); } + + private function importConfiguration(): void + { + $configuration = $this->get(ImportConfigurationRepository::class)->findByUid(1); + self::assertInstanceOf(ImportConfiguration::class, $configuration); + $this->get(Importer::class)->importConfiguration($configuration); + } } diff --git a/Tests/Unit/Domain/Import/EntityMapper/EntityRegistryTest.php b/Tests/Unit/Domain/Import/EntityMapper/EntityRegistryTest.php new file mode 100644 index 0000000..01bc871 --- /dev/null +++ b/Tests/Unit/Domain/Import/EntityMapper/EntityRegistryTest.php @@ -0,0 +1,50 @@ + + * + * 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\ThueCat\Tests\Unit\Domain\Import\EntityMapper; + +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; +use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\EntityRegistry; + +final class EntityRegistryTest extends TestCase +{ + #[Test] + public function returnsEntityWithHighestPriority(): void + { + $subject = new EntityRegistry(); + + $subject->registerEntityClass( + 'ClassA', + 10, + ['TypeA'] + ); + $subject->registerEntityClass( + 'ClassB', + 20, + ['TypeA'] + ); + + self::assertSame('ClassB', $subject->getEntityByTypes(['TypeA'])); + } +} diff --git a/Tests/Unit/Domain/Import/ImportTest.php b/Tests/Unit/Domain/Import/ImportTest.php index 403e40c..93bcd36 100644 --- a/Tests/Unit/Domain/Import/ImportTest.php +++ b/Tests/Unit/Domain/Import/ImportTest.php @@ -23,20 +23,16 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import; -use WerkraumMedia\ThueCat\Domain\Import\Import; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; +use WerkraumMedia\ThueCat\Domain\Import\Import; use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration; use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLog; use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLogEntry; -/** - * @covers \WerkraumMedia\ThueCat\Domain\Import\Import - */ class ImportTest extends TestCase { - /** - * @test - */ + #[Test] public function canBeCreated(): void { $subject = new Import(); @@ -47,9 +43,7 @@ class ImportTest extends TestCase ); } - /** - * @test - */ + #[Test] public function canStart(): void { $configuration = new ImportConfiguration(); @@ -66,9 +60,7 @@ class ImportTest extends TestCase ); } - /** - * @test - */ + #[Test] public function canEndAfterStart(): void { $configuration = new ImportConfiguration(); @@ -86,9 +78,7 @@ class ImportTest extends TestCase ); } - /** - * @test - */ + #[Test] public function isDoneAfterStartAndEnd(): void { $configuration = new ImportConfiguration(); @@ -99,9 +89,7 @@ class ImportTest extends TestCase self::assertTrue($subject->done()); } - /** - * @test - */ + #[Test] public function isNotDoneAfterJustStartWithoutEnd(): void { $configuration = new ImportConfiguration(); @@ -111,9 +99,7 @@ class ImportTest extends TestCase self::assertFalse($subject->done()); } - /** - * @test - */ + #[Test] public function nestedStartReturnsExpectedConfiguration(): void { $configuration1 = new ImportConfiguration(); @@ -129,9 +115,7 @@ class ImportTest extends TestCase ); } - /** - * @test - */ + #[Test] public function nestedStartReturnsExpectedLog(): void { $configuration1 = new ImportConfiguration(); @@ -159,9 +143,7 @@ class ImportTest extends TestCase ); } - /** - * @test - */ + #[Test] public function nestedImportMergesLog(): void { $configuration1 = new ImportConfiguration(); @@ -183,15 +165,13 @@ class ImportTest extends TestCase self::assertSame( [ - $importLogEntry + $importLogEntry, ], $log1->getEntries()->toArray() ); } - /** - * @test - */ + #[Test] public function nestedImportReturnsHandledForRemoteId(): void { $configuration1 = new ImportConfiguration(); diff --git a/Tests/Unit/Domain/Import/Importer/FetchDataTest.php b/Tests/Unit/Domain/Import/Importer/FetchDataTest.php index 107c695..d604e75 100644 --- a/Tests/Unit/Domain/Import/Importer/FetchDataTest.php +++ b/Tests/Unit/Domain/Import/Importer/FetchDataTest.php @@ -23,23 +23,21 @@ namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import\Importer; * 02110-1301, USA. */ +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestFactoryInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\StreamInterface; +use Psr\Http\Message\UriInterface; use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface; use WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData; use WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData\InvalidResponseException; -/** - * @covers \WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData - */ class FetchDataTest extends TestCase { - /** - * @test - */ + #[Test] public function canBeCreated(): void { $requestFactory = $this->createStub(RequestFactoryInterface::class); @@ -55,9 +53,7 @@ class FetchDataTest extends TestCase self::assertInstanceOf(FetchData::class, $subject); } - /** - * @test - */ + #[Test] public function returnsParsedJsonLdBasedOnUrl(): void { $requestFactory = $this->createStub(RequestFactoryInterface::class); @@ -70,8 +66,11 @@ class FetchDataTest extends TestCase $requestFactory->method('createRequest')->willReturn($request); $httpClient->method('sendRequest')->willReturn($response); + $body = $this->createStub(StreamInterface::class); + $body->method('__toString')->willReturn('{"@graph":[{"@id":"https://example.com/resources/018132452787-ngbe"}]}'); + $response->method('getStatusCode')->willReturn(200); - $response->method('getBody')->willReturn('{"@graph":[{"@id":"https://example.com/resources/018132452787-ngbe"}]}'); + $response->method('getBody')->willReturn($body); $subject = new FetchData( $requestFactory, @@ -89,9 +88,7 @@ class FetchDataTest extends TestCase ], $result); } - /** - * @test - */ + #[Test] public function returnsEmptyArrayInCaseOfError(): void { $requestFactory = $this->createStub(RequestFactoryInterface::class); @@ -105,8 +102,11 @@ class FetchDataTest extends TestCase $httpClient->method('sendRequest')->willReturn($response); + $body = $this->createStub(StreamInterface::class); + $body->method('__toString')->willReturn('[]'); + $response->method('getStatusCode')->willReturn(200); - $response->method('getBody')->willReturn(''); + $response->method('getBody')->willReturn($body); $subject = new FetchData( $requestFactory, @@ -118,9 +118,7 @@ class FetchDataTest extends TestCase self::assertSame([], $result); } - /** - * @test - */ + #[Test] public function returnsResultFromCacheIfAvailable(): void { $requestFactory = $this->createStub(RequestFactoryInterface::class); @@ -151,9 +149,7 @@ class FetchDataTest extends TestCase ], $result); } - /** - * @test - */ + #[Test] public function throwsExceptionOn404(): void { $requestFactory = $this->createStub(RequestFactoryInterface::class); @@ -163,14 +159,19 @@ class FetchDataTest extends TestCase $request = $this->createStub(RequestInterface::class); $response = $this->createStub(ResponseInterface::class); - $request->method('getUri')->willReturn('https://example.com/resources/018132452787-ngbe'); + $uri = $this->createStub(UriInterface::class); + $uri->method('__toString')->willReturn('https://example.com/resources/018132452787-ngbe'); + $request->method('getUri')->willReturn($uri); $requestFactory->method('createRequest')->willReturn($request); $httpClient->method('sendRequest')->willReturn($response); + $body = $this->createStub(StreamInterface::class); + $body->method('__toString')->willReturn('{"error":"404"}'); + $response->method('getStatusCode')->willReturn(404); - $response->method('getBody')->willReturn('{"error":"404"}'); + $response->method('getBody')->willReturn($body); $subject = new FetchData( $requestFactory, @@ -185,9 +186,7 @@ class FetchDataTest extends TestCase $subject->jsonLDFromUrl('https://example.com/resources/018132452787-ngbe'); } - /** - * @test - */ + #[Test] public function throwsExceptionOn401(): void { $requestFactory = $this->createStub(RequestFactoryInterface::class); diff --git a/Tests/Unit/Domain/Import/Model/EntityCollectionTest.php b/Tests/Unit/Domain/Import/Model/EntityCollectionTest.php index 1864a99..674010d 100644 --- a/Tests/Unit/Domain/Import/Model/EntityCollectionTest.php +++ b/Tests/Unit/Domain/Import/Model/EntityCollectionTest.php @@ -23,18 +23,14 @@ namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import\Model; * 02110-1301, USA. */ +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use WerkraumMedia\ThueCat\Domain\Import\Model\Entity; use WerkraumMedia\ThueCat\Domain\Import\Model\EntityCollection; -/** - * @covers \WerkraumMedia\ThueCat\Domain\Import\Model\EntityCollection - */ class EntityCollectionTest extends TestCase { - /** - * @test - */ + #[Test] public function canBeCreated(): void { $subject = new EntityCollection(); @@ -42,9 +38,7 @@ class EntityCollectionTest extends TestCase self::assertInstanceOf(EntityCollection::class, $subject); } - /** - * @test - */ + #[Test] public function returnsEmptyArrayAsDefaultEntities(): void { $subject = new EntityCollection(); @@ -52,9 +46,7 @@ class EntityCollectionTest extends TestCase self::assertSame([], $subject->getEntities()); } - /** - * @test - */ + #[Test] public function returnsFirstEntityForDefaultLanguage(): void { $entityWithTranslation = $this->createStub(Entity::class); @@ -73,9 +65,7 @@ class EntityCollectionTest extends TestCase ); } - /** - * @test - */ + #[Test] public function returnsNullIfNoEntityForDefaultLanguageExists(): void { $entityWithTranslation = $this->createStub(Entity::class); @@ -89,9 +79,7 @@ class EntityCollectionTest extends TestCase ); } - /** - * @test - */ + #[Test] public function returnsEntitiesToTranslate(): void { $entityWithTranslation = $this->createStub(Entity::class); @@ -109,9 +97,7 @@ class EntityCollectionTest extends TestCase ); } - /** - * @test - */ + #[Test] public function returnsExistingEntities(): void { $entityWithTranslation = $this->createStub(Entity::class); diff --git a/Tests/Unit/Domain/Import/Model/GenericEntityTest.php b/Tests/Unit/Domain/Import/Model/GenericEntityTest.php index e02cf20..6d5a129 100644 --- a/Tests/Unit/Domain/Import/Model/GenericEntityTest.php +++ b/Tests/Unit/Domain/Import/Model/GenericEntityTest.php @@ -23,17 +23,13 @@ namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import\Model; * 02110-1301, USA. */ +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use WerkraumMedia\ThueCat\Domain\Import\Model\GenericEntity; -/** - * @covers \WerkraumMedia\ThueCat\Domain\Import\Model\GenericEntity - */ class GenericEntityTest extends TestCase { - /** - * @test - */ + #[Test] public function canBeCreated(): void { $subject = new GenericEntity( @@ -46,9 +42,7 @@ class GenericEntityTest extends TestCase self::assertInstanceOf(GenericEntity::class, $subject); } - /** - * @test - */ + #[Test] public function returnsTypo3StoragePid(): void { $subject = new GenericEntity( @@ -61,9 +55,7 @@ class GenericEntityTest extends TestCase self::assertSame(10, $subject->getTypo3StoragePid()); } - /** - * @test - */ + #[Test] public function returnsTypo3DatabaseTableName(): void { $subject = new GenericEntity( @@ -76,9 +68,7 @@ class GenericEntityTest extends TestCase self::assertSame('tx_thuecat_entity', $subject->getTypo3DatabaseTableName()); } - /** - * @test - */ + #[Test] public function returnsTypo3SystemLanguageUid(): void { $subject = new GenericEntity( @@ -91,9 +81,7 @@ class GenericEntityTest extends TestCase self::assertSame(10, $subject->getTypo3SystemLanguageUid()); } - /** - * @test - */ + #[Test] public function claimsIsForDefaultLanguage(): void { $subject = new GenericEntity( @@ -106,9 +94,7 @@ class GenericEntityTest extends TestCase self::assertTrue($subject->isForDefaultLanguage()); } - /** - * @test - */ + #[Test] public function claimsIsTranslation(): void { $subject = new GenericEntity( @@ -121,9 +107,7 @@ class GenericEntityTest extends TestCase self::assertTrue($subject->isTranslation()); } - /** - * @test - */ + #[Test] public function returnsRemoteId(): void { $subject = new GenericEntity( @@ -139,9 +123,7 @@ class GenericEntityTest extends TestCase ); } - /** - * @test - */ + #[Test] public function returnsData(): void { $subject = new GenericEntity( @@ -163,9 +145,7 @@ class GenericEntityTest extends TestCase ); } - /** - * @test - */ + #[Test] public function returnsNotCreatedByDefault(): void { $subject = new GenericEntity( @@ -180,9 +160,7 @@ class GenericEntityTest extends TestCase ); } - /** - * @test - */ + #[Test] public function returnsNotExistingByDefault(): void { $subject = new GenericEntity( @@ -197,9 +175,7 @@ class GenericEntityTest extends TestCase ); } - /** - * @test - */ + #[Test] public function returnsZeroAsDefaultTypo3Uid(): void { $subject = new GenericEntity( @@ -215,9 +191,7 @@ class GenericEntityTest extends TestCase ); } - /** - * @test - */ + #[Test] public function canBeMarkedAsImported(): void { $subject = new GenericEntity( @@ -234,9 +208,7 @@ class GenericEntityTest extends TestCase self::assertSame(10, $subject->getTypo3Uid()); } - /** - * @test - */ + #[Test] public function canBeMarkedAsExisting(): void { $subject = new GenericEntity( diff --git a/Tests/Unit/Domain/Import/RequestFactoryTest.php b/Tests/Unit/Domain/Import/RequestFactoryTest.php index 73dae8e..54306d4 100644 --- a/Tests/Unit/Domain/Import/RequestFactoryTest.php +++ b/Tests/Unit/Domain/Import/RequestFactoryTest.php @@ -23,25 +23,22 @@ namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import; * 02110-1301, USA. */ +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use TYPO3\CMS\Core\Configuration\Exception\ExtensionConfigurationExtensionNotConfiguredException; use TYPO3\CMS\Core\Configuration\ExtensionConfiguration; +use TYPO3\CMS\Core\Http\Client\GuzzleClientFactory; use TYPO3\CMS\Core\Http\RequestFactory as Typo3RequestFactory; use TYPO3\CMS\Core\Http\UriFactory; use WerkraumMedia\ThueCat\Domain\Import\RequestFactory; -/** - * @covers \WerkraumMedia\ThueCat\Domain\Import\RequestFactory - */ class RequestFactoryTest extends TestCase { - /** - * @test - */ + #[Test] public function canBeCreated(): void { $extensionConfiguration = $this->createStub(ExtensionConfiguration::class); - $requestFactory = new Typo3RequestFactory(); + $requestFactory = $this->createStub(Typo3RequestFactory::class); $uriFactory = new UriFactory(); $subject = new RequestFactory( @@ -53,13 +50,11 @@ class RequestFactoryTest extends TestCase self::assertInstanceOf(RequestFactory::class, $subject); } - /** - * @test - */ + #[Test] public function returnsRequestWithJsonIdFormat(): void { $extensionConfiguration = $this->createStub(ExtensionConfiguration::class); - $requestFactory = new Typo3RequestFactory(); + $requestFactory = new Typo3RequestFactory($this->createStub(GuzzleClientFactory::class)); $uriFactory = new UriFactory(); $subject = new RequestFactory( @@ -73,14 +68,12 @@ class RequestFactoryTest extends TestCase self::assertSame('syncScopeId=dd3738dc-58a6-4748-a6ce-4950293a06db&format=jsonld', $request->getUri()->getQuery()); } - /** - * @test - */ + #[Test] public function returnsRequestWithApiKeyWhenConfigured(): void { $extensionConfiguration = $this->createStub(ExtensionConfiguration::class); $extensionConfiguration->method('get')->willReturn('some-api-key'); - $requestFactory = new Typo3RequestFactory(); + $requestFactory = new Typo3RequestFactory($this->createStub(GuzzleClientFactory::class)); $uriFactory = new UriFactory(); $subject = new RequestFactory( @@ -94,14 +87,12 @@ class RequestFactoryTest extends TestCase self::assertSame('syncScopeId=dd3738dc-58a6-4748-a6ce-4950293a06db&format=jsonld&api_key=some-api-key', $request->getUri()->getQuery()); } - /** - * @test - */ + #[Test] public function returnsRequestWithoutApiKeyWhenUnkown(): void { $extensionConfiguration = $this->createStub(ExtensionConfiguration::class); $extensionConfiguration->method('get')->willThrowException(new ExtensionConfigurationExtensionNotConfiguredException()); - $requestFactory = new Typo3RequestFactory(); + $requestFactory = new Typo3RequestFactory($this->createStub(GuzzleClientFactory::class)); $uriFactory = new UriFactory(); $subject = new RequestFactory( diff --git a/Tests/Unit/Domain/Import/Typo3Converter/GeneralConverterTest.php b/Tests/Unit/Domain/Import/Typo3Converter/GeneralConverterTest.php index 699aec0..34eba57 100644 --- a/Tests/Unit/Domain/Import/Typo3Converter/GeneralConverterTest.php +++ b/Tests/Unit/Domain/Import/Typo3Converter/GeneralConverterTest.php @@ -23,14 +23,15 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import\Typo3Converter; -use TYPO3\CMS\Core\Log\LogManager; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; use TYPO3\CMS\Core\Log\Logger; +use TYPO3\CMS\Core\Log\LogManager; use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\ForeignReference; use WerkraumMedia\ThueCat\Domain\Import\Entity\Town; use WerkraumMedia\ThueCat\Domain\Import\Importer; -use WerkraumMedia\ThueCat\Domain\Import\Typo3Converter\GeneralConverter; -use PHPUnit\Framework\TestCase; use WerkraumMedia\ThueCat\Domain\Import\ResolveForeignReference; +use WerkraumMedia\ThueCat\Domain\Import\Typo3Converter\GeneralConverter; use WerkraumMedia\ThueCat\Domain\Import\Typo3Converter\LanguageHandling; use WerkraumMedia\ThueCat\Domain\Import\Typo3Converter\NameExtractor; use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration; @@ -39,14 +40,9 @@ use WerkraumMedia\ThueCat\Domain\Repository\Backend\OrganisationRepository; use WerkraumMedia\ThueCat\Domain\Repository\Backend\ParkingFacilityRepository; use WerkraumMedia\ThueCat\Domain\Repository\Backend\TownRepository; -/** - * @covers \WerkraumMedia\ThueCat\Domain\Import\Typo3Converter\GeneralConverter - */ class GeneralConverterTest extends TestCase { - /** - * @test - */ + #[Test] public function canBeCreated(): void { $resolveForeignReference = $this->createStub(ResolveForeignReference::class); @@ -57,6 +53,7 @@ class GeneralConverterTest extends TestCase $parkingFacilityRepository = $this->createStub(ParkingFacilityRepository::class); $nameExtractor = $this->createStub(NameExtractor::class); $logManager = $this->createStub(LogManager::class); + $logManager->method('getLogger')->willReturn($this->createStub(Logger::class)); $subject = new GeneralConverter( $resolveForeignReference, @@ -75,9 +72,7 @@ class GeneralConverterTest extends TestCase ); } - /** - * @test - */ + #[Test] public function skipsWithoutManager(): void { $resolveForeignReference = $this->createStub(ResolveForeignReference::class); diff --git a/Tests/Unit/Domain/Import/Typo3Converter/NameExtractorTest.php b/Tests/Unit/Domain/Import/Typo3Converter/NameExtractorTest.php index 50d3e18..c1d175d 100644 --- a/Tests/Unit/Domain/Import/Typo3Converter/NameExtractorTest.php +++ b/Tests/Unit/Domain/Import/Typo3Converter/NameExtractorTest.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import\Typo3Converter; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\MockObject\Stub; use PHPUnit\Framework\TestCase; use WerkraumMedia\ThueCat\Domain\Import\Entity\Person; @@ -31,14 +32,9 @@ use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\ForeignReference; use WerkraumMedia\ThueCat\Domain\Import\ResolveForeignReference; use WerkraumMedia\ThueCat\Domain\Import\Typo3Converter\NameExtractor; -/** - * @covers \WerkraumMedia\ThueCat\Domain\Import\Typo3Converter\NameExtractor - */ class NameExtractorTest extends TestCase { - /** - * @test - */ + #[Test] public function canBeCreated(): void { $resolveForeignReference = $this->createStub(ResolveForeignReference::class); @@ -53,9 +49,7 @@ class NameExtractorTest extends TestCase ); } - /** - * @test - */ + #[Test] public function extractsNameFromString(): void { $resolveForeignReference = $this->createStub(ResolveForeignReference::class); @@ -70,9 +64,7 @@ class NameExtractorTest extends TestCase ); } - /** - * @test - */ + #[Test] public function extractsNameFromForeignReference(): void { $place = $this->createStub(Place::class); @@ -91,9 +83,7 @@ class NameExtractorTest extends TestCase ); } - /** - * @test - */ + #[Test] public function extractsCombinedNameFromForeignReference(): void { $person = $this->createStub(Person::class); @@ -113,9 +103,7 @@ class NameExtractorTest extends TestCase ); } - /** - * @test - */ + #[Test] public function extractsCombinedNameFromForeignReferenceInsteadOfName(): void { $person = $this->createStub(Person::class); diff --git a/Tests/Unit/Domain/Import/UrlProvider/RegistryTest.php b/Tests/Unit/Domain/Import/UrlProvider/RegistryTest.php index af77d8b..a0f1f62 100644 --- a/Tests/Unit/Domain/Import/UrlProvider/RegistryTest.php +++ b/Tests/Unit/Domain/Import/UrlProvider/RegistryTest.php @@ -23,19 +23,15 @@ namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import\UrlProvider; * 02110-1301, USA. */ +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use WerkraumMedia\ThueCat\Domain\Import\UrlProvider\Registry; use WerkraumMedia\ThueCat\Domain\Import\UrlProvider\StaticUrlProvider; use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration; -/** - * @covers \WerkraumMedia\ThueCat\Domain\Import\UrlProvider\Registry - */ class RegistryTest extends TestCase { - /** - * @test - */ + #[Test] public function canBeCreated(): void { $subject = new Registry(); @@ -43,9 +39,7 @@ class RegistryTest extends TestCase self::assertInstanceOf(Registry::class, $subject); } - /** - * @test - */ + #[Test] public function allowsRegistrationOfUrlProvider(): void { $subject = new Registry(); @@ -55,9 +49,7 @@ class RegistryTest extends TestCase self::assertTrue(true); } - /** - * @test - */ + #[Test] public function returnsNullIfNoProviderExistsForConfiguration(): void { $configuration = new ImportConfiguration(); @@ -68,9 +60,7 @@ class RegistryTest extends TestCase self::assertNull($result); } - /** - * @test - */ + #[Test] public function returnsProviderForConfiguration(): void { $configuration = new ImportConfiguration(); diff --git a/Tests/Unit/Domain/Import/UrlProvider/StaticUrlProviderTest.php b/Tests/Unit/Domain/Import/UrlProvider/StaticUrlProviderTest.php index 58e1122..ea04d46 100644 --- a/Tests/Unit/Domain/Import/UrlProvider/StaticUrlProviderTest.php +++ b/Tests/Unit/Domain/Import/UrlProvider/StaticUrlProviderTest.php @@ -23,27 +23,21 @@ namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import\UrlProvider; * 02110-1301, USA. */ +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use WerkraumMedia\ThueCat\Domain\Import\UrlProvider\StaticUrlProvider; use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration; -/** - * @covers \WerkraumMedia\ThueCat\Domain\Import\UrlProvider\StaticUrlProvider - */ class StaticUrlProviderTest extends TestCase { - /** - * @test - */ + #[Test] public function canBeCreated(): void { $subject = new StaticUrlProvider(); self::assertInstanceOf(StaticUrlProvider::class, $subject); } - /** - * @test - */ + #[Test] public function canProvideForStaticConfiguration(): void { $configuration = new ImportConfiguration(); @@ -55,9 +49,7 @@ class StaticUrlProviderTest extends TestCase self::assertTrue($result); } - /** - * @test - */ + #[Test] public function returnsConcreteProviderForConfiguration(): void { $configuration = new ImportConfiguration(); @@ -69,9 +61,7 @@ class StaticUrlProviderTest extends TestCase self::assertInstanceOf(StaticUrlProvider::class, $result); } - /** - * @test - */ + #[Test] public function concreteProviderReturnsUrls(): void { $configuration = new ImportConfiguration(); diff --git a/Tests/Unit/Domain/Import/UrlProvider/SyncScopeUrlProviderTest.php b/Tests/Unit/Domain/Import/UrlProvider/SyncScopeUrlProviderTest.php index 563345f..085cd03 100644 --- a/Tests/Unit/Domain/Import/UrlProvider/SyncScopeUrlProviderTest.php +++ b/Tests/Unit/Domain/Import/UrlProvider/SyncScopeUrlProviderTest.php @@ -23,19 +23,15 @@ namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import\UrlProvider; * 02110-1301, USA. */ +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; use WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData; use WerkraumMedia\ThueCat\Domain\Import\UrlProvider\SyncScopeUrlProvider; -use PHPUnit\Framework\TestCase; use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration; -/** - * @covers \WerkraumMedia\ThueCat\Domain\Import\UrlProvider\SyncScopeUrlProvider - */ class SyncScopeUrlProviderTest extends TestCase { - /** - * @test - */ + #[Test] public function canBeCreated(): void { $fetchData = $this->createStub(FetchData::class); @@ -47,9 +43,7 @@ class SyncScopeUrlProviderTest extends TestCase self::assertInstanceOf(SyncScopeUrlProvider::class, $subject); } - /** - * @test - */ + #[Test] public function canProvideForSyncScope(): void { $configuration = new ImportConfiguration(); @@ -65,9 +59,7 @@ class SyncScopeUrlProviderTest extends TestCase self::assertTrue($result); } - /** - * @test - */ + #[Test] public function returnsConcreteProviderForConfiguration(): void { $configuration = new ImportConfiguration(); @@ -92,9 +84,7 @@ class SyncScopeUrlProviderTest extends TestCase self::assertInstanceOf(SyncScopeUrlProvider::class, $result); } - /** - * @test - */ + #[Test] public function concreteProviderReturnsUrls(): void { $configuration = new ImportConfiguration(); diff --git a/Tests/Unit/Domain/Model/Backend/ImportConfigurationTest.php b/Tests/Unit/Domain/Model/Backend/ImportConfigurationTest.php index 9c7bfc4..3fba4ec 100644 --- a/Tests/Unit/Domain/Model/Backend/ImportConfigurationTest.php +++ b/Tests/Unit/Domain/Model/Backend/ImportConfigurationTest.php @@ -23,17 +23,14 @@ namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Model\Backend; * 02110-1301, USA. */ +use DateTimeImmutable; +use PHPUnit\Framework\Attributes\Test; use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase as TestCase; use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration; -/** - * @covers \WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration - */ class ImportConfigurationTest extends TestCase { - /** - * @test - */ + #[Test] public function canBeCreated(): void { $subject = new ImportConfiguration(); @@ -41,9 +38,7 @@ class ImportConfigurationTest extends TestCase self::assertInstanceOf(ImportConfiguration::class, $subject); } - /** - * @test - */ + #[Test] public function returnsTitle(): void { $subject = new ImportConfiguration(); @@ -52,9 +47,7 @@ class ImportConfigurationTest extends TestCase self::assertSame('Example Title', $subject->getTitle()); } - /** - * @test - */ + #[Test] public function returnsType(): void { $subject = new ImportConfiguration(); @@ -63,9 +56,7 @@ class ImportConfigurationTest extends TestCase self::assertSame('static', $subject->getType()); } - /** - * @test - */ + #[Test] public function returnsTableName(): void { $subject = new ImportConfiguration(); @@ -73,12 +64,10 @@ class ImportConfigurationTest extends TestCase self::assertSame('tx_thuecat_import_configuration', $subject->getTableName()); } - /** - * @test - */ + #[Test] public function returnsLastChanged(): void { - $lastChanged = new \DateTimeImmutable(); + $lastChanged = new DateTimeImmutable(); $subject = new ImportConfiguration(); @@ -87,23 +76,21 @@ class ImportConfigurationTest extends TestCase self::assertSame($lastChanged, $subject->getLastChanged()); } - /** - * @test - */ + #[Test] public function returnsStoragePidWhenSet(): void { $flexForm = implode(PHP_EOL, [ '', '', - '', - '', - '', - '', - '20', - '', - '', - '', - '', + '', + '', + '', + '', + '20', + '', + '', + '', + '', '', ]); @@ -114,9 +101,7 @@ class ImportConfigurationTest extends TestCase self::assertSame(20, $subject->getStoragePid()); } - /** - * @test - */ + #[Test] public function returnsZeroAsStoragePidWhenNoConfigurationExists(): void { $flexForm = ''; @@ -128,23 +113,21 @@ class ImportConfigurationTest extends TestCase self::assertSame(0, $subject->getStoragePid()); } - /** - * @test - */ + #[Test] public function returnsZeroAsStoragePidWhenNegativePidIsConfigured(): void { $flexForm = implode(PHP_EOL, [ '', '', - '', - '', - '', - '', - '-1', - '', - '', - '', - '', + '', + '', + '', + '', + '-1', + '', + '', + '', + '', '', ]); @@ -155,23 +138,21 @@ class ImportConfigurationTest extends TestCase self::assertSame(0, $subject->getStoragePid()); } - /** - * @test - */ + #[Test] public function returnsZeroAsStoragePidWhenNoneNumericPidIsConfigured(): void { $flexForm = implode(PHP_EOL, [ '', '', - '', - '', - '', - '', - 'abc', - '', - '', - '', - '', + '', + '', + '', + '', + 'abc', + '', + '', + '', + '', '', ]); @@ -182,34 +163,32 @@ class ImportConfigurationTest extends TestCase self::assertSame(0, $subject->getStoragePid()); } - /** - * @test - */ + #[Test] public function returnsUrlsWhenSet(): void { $flexForm = implode(PHP_EOL, [ '', '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - 'https://thuecat.org/resources/942302009360-jopp', - '', - '', - '', - '0', - '', - '', - '', - '', - '', - '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + 'https://thuecat.org/resources/942302009360-jopp', + '', + '', + '', + '0', + '', + '', + '', + '', + '', + '', '', ]); @@ -222,9 +201,7 @@ class ImportConfigurationTest extends TestCase ], $subject->getUrls()); } - /** - * @test - */ + #[Test] public function returnsEmptyArrayAsUrlsWhenNoConfigurationExists(): void { $flexForm = ''; @@ -236,23 +213,21 @@ class ImportConfigurationTest extends TestCase self::assertSame([], $subject->getUrls()); } - /** - * @test - */ + #[Test] public function returnsEmptyArrayAsUrlsWhenNoUrlsAreConfigured(): void { $flexForm = implode(PHP_EOL, [ '', '', - '', - '', - '', - '', - '10', - '', - '', - '', - '', + '', + '', + '', + '', + '10', + '', + '', + '', + '', '', ]); @@ -263,23 +238,21 @@ class ImportConfigurationTest extends TestCase self::assertSame([], $subject->getUrls()); } - /** - * @test - */ + #[Test] public function returnsSyncScopeIdWhenSet(): void { $flexForm = implode(PHP_EOL, [ '', '', - '', - '', - '', - '', - 'dd4639dc-58a7-4648-a6ce-4950293a06db', - '', - '', - '', - '', + '', + '', + '', + '', + 'dd4639dc-58a7-4648-a6ce-4950293a06db', + '', + '', + '', + '', '', ]); @@ -290,9 +263,7 @@ class ImportConfigurationTest extends TestCase self::assertSame('dd4639dc-58a7-4648-a6ce-4950293a06db', $subject->getSyncScopeId()); } - /** - * @test - */ + #[Test] public function returnsEmptyStringAsSyncScopeIdWhenNoConfigurationExists(): void { $flexForm = ''; @@ -304,23 +275,21 @@ class ImportConfigurationTest extends TestCase self::assertSame('', $subject->getSyncScopeId()); } - /** - * @test - */ + #[Test] public function returnsEmptyStringAsSyncScopeIdWhenNoSyncScopeIdAreConfigured(): void { $flexForm = implode(PHP_EOL, [ '', '', - '', - '', - '', - '', - '10', - '', - '', - '', - '', + '', + '', + '', + '', + '10', + '', + '', + '', + '', '', ]); diff --git a/Tests/Unit/Domain/Model/Backend/ImportLogTest.php b/Tests/Unit/Domain/Model/Backend/ImportLogTest.php index 2d19474..3369e39 100644 --- a/Tests/Unit/Domain/Model/Backend/ImportLogTest.php +++ b/Tests/Unit/Domain/Model/Backend/ImportLogTest.php @@ -23,18 +23,14 @@ namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Model\Backend; * 02110-1301, USA. */ +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration; use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLog; -use PHPUnit\Framework\TestCase; -/** - * @covers \WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLog - */ class ImportLogTest extends TestCase { - /** - * @test - */ + #[Test] public function canBeCreated(): void { $subject = new ImportLog(); @@ -42,9 +38,7 @@ class ImportLogTest extends TestCase self::assertInstanceOf(ImportLog::class, $subject); } - /** - * @test - */ + #[Test] public function returnsConfigurationIfSet(): void { $configuration = new ImportConfiguration(); @@ -53,9 +47,7 @@ class ImportLogTest extends TestCase self::assertSame($configuration, $subject->getConfiguration()); } - /** - * @test - */ + #[Test] public function returnsNullForConfigurationIfNotSet(): void { $subject = new ImportLog(); @@ -63,9 +55,7 @@ class ImportLogTest extends TestCase self::assertNull($subject->getConfiguration()); } - /** - * @test - */ + #[Test] public function returnsConfigurationUidIfSet(): void { $configuration = new ImportConfiguration(); @@ -75,9 +65,7 @@ class ImportLogTest extends TestCase self::assertSame(10, $subject->getConfigurationUid()); } - /** - * @test - */ + #[Test] public function returnsZeroForConfigurationIfNotSet(): void { $subject = new ImportLog(); diff --git a/Tests/Unit/Domain/Model/Frontend/AddressTest.php b/Tests/Unit/Domain/Model/Frontend/AddressTest.php index 0530066..5042e54 100644 --- a/Tests/Unit/Domain/Model/Frontend/AddressTest.php +++ b/Tests/Unit/Domain/Model/Frontend/AddressTest.php @@ -23,17 +23,13 @@ namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Model\Frontend; * 02110-1301, USA. */ +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use WerkraumMedia\ThueCat\Domain\Model\Frontend\Address; -/** - * @covers \WerkraumMedia\ThueCat\Domain\Model\Frontend\Address - */ class AddressTest extends TestCase { - /** - * @test - */ + #[Test] public function canBeCreated(): void { $subject = new Address('[]'); @@ -41,9 +37,7 @@ class AddressTest extends TestCase self::assertInstanceOf(Address::class, $subject); } - /** - * @test - */ + #[Test] public function returnsProperDefaults(): void { $subject = new Address('[]'); @@ -56,9 +50,7 @@ class AddressTest extends TestCase self::assertSame('', $subject->getFax()); } - /** - * @test - */ + #[Test] public function returnsStreet(): void { $subject = new Address('{"street": "Example Street 10"}'); @@ -66,9 +58,7 @@ class AddressTest extends TestCase self::assertSame('Example Street 10', $subject->getStreet()); } - /** - * @test - */ + #[Test] public function returnsZip(): void { $subject = new Address('{"zip": "09084"}'); @@ -76,9 +66,7 @@ class AddressTest extends TestCase self::assertSame('09084', $subject->getZip()); } - /** - * @test - */ + #[Test] public function returnsCity(): void { $subject = new Address('{"city": "Erfurt"}'); @@ -86,9 +74,7 @@ class AddressTest extends TestCase self::assertSame('Erfurt', $subject->getCity()); } - /** - * @test - */ + #[Test] public function returnsEmail(): void { $subject = new Address('{"email": "example@example.com"}'); @@ -96,9 +82,7 @@ class AddressTest extends TestCase self::assertSame('example@example.com', $subject->getEmail()); } - /** - * @test - */ + #[Test] public function returnsPhone(): void { $subject = new Address('{"phone": "+49 361 99999"}'); @@ -106,9 +90,7 @@ class AddressTest extends TestCase self::assertSame('+49 361 99999', $subject->getPhone()); } - /** - * @test - */ + #[Test] public function returnsFax(): void { $subject = new Address('{"fax": "+49 361 99998"}'); @@ -116,9 +98,7 @@ class AddressTest extends TestCase self::assertSame('+49 361 99998', $subject->getFax()); } - /** - * @test - */ + #[Test] public function returnsLatitude(): void { $subject = new Address('{"geo": {"latitude": 50.978765}}'); @@ -126,9 +106,7 @@ class AddressTest extends TestCase self::assertSame(50.978765, $subject->getLatitute()); } - /** - * @test - */ + #[Test] public function returnsLongitude(): void { $subject = new Address('{"geo": {"longitude": 11.029133}}'); @@ -136,13 +114,11 @@ class AddressTest extends TestCase self::assertSame(11.029133, $subject->getLongitude()); } - /** - * @test - */ + #[Test] public function returnsSerializedString(): void { $subject = new Address('{"street": "Example Street 10"}'); - self::assertSame('{"street": "Example Street 10"}', (string) $subject); + self::assertSame('{"street": "Example Street 10"}', (string)$subject); } } diff --git a/Tests/Unit/Domain/Model/Frontend/MediaTest.php b/Tests/Unit/Domain/Model/Frontend/MediaTest.php index f41f15d..0b08d64 100644 --- a/Tests/Unit/Domain/Model/Frontend/MediaTest.php +++ b/Tests/Unit/Domain/Model/Frontend/MediaTest.php @@ -23,18 +23,14 @@ namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Model\Frontend; * 02110-1301, USA. */ +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use TYPO3\CMS\Core\Resource\FileReference; use WerkraumMedia\ThueCat\Domain\Model\Frontend\Media; -/** - * @covers \WerkraumMedia\ThueCat\Domain\Model\Frontend\Media - */ class MediaTest extends TestCase { - /** - * @test - */ + #[Test] public function canBeCreated(): void { $subject = new Media('[]'); @@ -42,9 +38,7 @@ class MediaTest extends TestCase self::assertInstanceOf(Media::class, $subject); } - /** - * @test - */ + #[Test] public function returnsMainImageIfPresent(): void { $subject = new Media('[{"mainImage":false,"type":"image","title":"Erfurt-Dom-und-Severikirche.jpg"},{"mainImage":true,"type":"image","title":"Erfurt-Dom und Severikirche-beleuchtet.jpg"}]'); @@ -56,9 +50,7 @@ class MediaTest extends TestCase ], $subject->getMainImage()); } - /** - * @test - */ + #[Test] public function returnsEmptyArrayAsMainImageFallback(): void { $subject = new Media('[]'); @@ -66,9 +58,7 @@ class MediaTest extends TestCase self::assertSame([], $subject->getMainImage()); } - /** - * @test - */ + #[Test] public function returnsImagesAsArray(): void { $subject = new Media('[{"mainImage":false,"type":"image","title":"Erfurt-Dom-und-Severikirche.jpg"},{"mainImage":true,"type":"image","title":"Erfurt-Dom und Severikirche-beleuchtet.jpg"}]'); @@ -87,9 +77,7 @@ class MediaTest extends TestCase ], $subject->getImages()); } - /** - * @test - */ + #[Test] public function returnsExtraImagesAsArray(): void { $subject = new Media('[{"mainImage":false,"type":"image","title":"Erfurt-Dom-und-Severikirche.jpg"},{"mainImage":true,"type":"image","title":"Erfurt-Dom und Severikirche-beleuchtet.jpg"}]'); @@ -103,9 +91,7 @@ class MediaTest extends TestCase ], $subject->getExtraImages()); } - /** - * @test - */ + #[Test] public function doesNotAddCopyrightAuthorIfItDoesntExist(): void { $subject = new Media(json_encode([ @@ -131,9 +117,7 @@ class MediaTest extends TestCase ); } - /** - * @test - */ + #[Test] public function addsCopyrightAuthorFromLicenseAuthor(): void { $subject = new Media(json_encode([ @@ -165,9 +149,7 @@ class MediaTest extends TestCase ); } - /** - * @test - */ + #[Test] public function addsCopyrightAuthorFromAuthor(): void { $subject = new Media(json_encode([ @@ -195,9 +177,7 @@ class MediaTest extends TestCase ); } - /** - * @test - */ + #[Test] public function addsCopyrightAuthorFromAuthorWithHigherPrio(): void { $subject = new Media(json_encode([ @@ -231,9 +211,7 @@ class MediaTest extends TestCase ); } - /** - * @test - */ + #[Test] public function returnsEmptyArrayAsDefaultForEditorialImages(): void { $subject = new Media(''); @@ -243,9 +221,7 @@ class MediaTest extends TestCase ); } - /** - * @test - */ + #[Test] public function returnsSetEditorialImages(): void { $subject = new Media(''); @@ -263,9 +239,7 @@ class MediaTest extends TestCase self::assertSame($reference2, $images[1]); } - /** - * @test - */ + #[Test] public function returnsEmptyArrayAsDefaultForAllImages(): void { $subject = new Media(''); @@ -275,9 +249,7 @@ class MediaTest extends TestCase ); } - /** - * @test - */ + #[Test] public function returnsAllImages(): void { $subject = new Media(json_encode([ diff --git a/Tests/Unit/Domain/Model/Frontend/OfferTest.php b/Tests/Unit/Domain/Model/Frontend/OfferTest.php index dda9021..bfbb920 100644 --- a/Tests/Unit/Domain/Model/Frontend/OfferTest.php +++ b/Tests/Unit/Domain/Model/Frontend/OfferTest.php @@ -23,17 +23,13 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Model\Frontend; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use WerkraumMedia\ThueCat\Domain\Model\Frontend\Offer; -/** - * @covers \WerkraumMedia\ThueCat\Domain\Model\Frontend\Offer - */ class OfferTest extends TestCase { - /** - * @test - */ + #[Test] public function canBeCreatedWithLegacyTypeAsString(): void { $subject = Offer::createFromArray([ @@ -51,9 +47,7 @@ class OfferTest extends TestCase self::assertSame('LegacyType', $subject->getType()); } - /** - * @test - */ + #[Test] public function canBeCreatedWithSingleType(): void { $subject = Offer::createFromArray([ @@ -71,9 +65,7 @@ class OfferTest extends TestCase self::assertSame('ParkingFee', $subject->getType()); } - /** - * @test - */ + #[Test] public function canBeCreatedWithMultipleTypes(): void { $subject = Offer::createFromArray([ @@ -91,9 +83,7 @@ class OfferTest extends TestCase self::assertSame('CourseOffer', $subject->getType()); } - /** - * @test - */ + #[Test] public function canBeCreatedWithoutType(): void { $subject = Offer::createFromArray([ diff --git a/Tests/Unit/Domain/Model/Frontend/OffersTest.php b/Tests/Unit/Domain/Model/Frontend/OffersTest.php index 6e929a3..d0a0c73 100644 --- a/Tests/Unit/Domain/Model/Frontend/OffersTest.php +++ b/Tests/Unit/Domain/Model/Frontend/OffersTest.php @@ -23,22 +23,16 @@ namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Model\Frontend; * 02110-1301, USA. */ +use Countable; +use Iterator; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use WerkraumMedia\ThueCat\Domain\Model\Frontend\Offers; -/** - * @covers \WerkraumMedia\ThueCat\Domain\Model\Frontend\Offers - * - * @uses \WerkraumMedia\ThueCat\Domain\Model\Frontend\Offer - * @uses \WerkraumMedia\ThueCat\Domain\Model\Frontend\Price - * - * @testdox Frontend model for offers - */ class OffersTest extends TestCase { - /** - * @test - */ + #[Test] public function canBeCreated(): void { $subject = new Offers('{}'); @@ -46,31 +40,24 @@ class OffersTest extends TestCase self::assertInstanceOf(Offers::class, $subject); } - /** - * @test - */ + #[Test] public function isCountable(): void { $subject = new Offers('{}'); - self::assertInstanceOf(\Countable::class, $subject); + self::assertInstanceOf(Countable::class, $subject); } - /** - * @test - */ + #[Test] public function isIterator(): void { $subject = new Offers('{}'); - self::assertInstanceOf(\Iterator::class, $subject); + self::assertInstanceOf(Iterator::class, $subject); } - /** - * @test - * @dataProvider forCount - * @testdox returns $expected for count - */ + #[Test] + #[DataProvider('forCount')] public function returnsExpectedCount(string $serialized, int $expected): void { $subject = new Offers($serialized); @@ -78,7 +65,7 @@ class OffersTest extends TestCase self::assertCount($expected, $subject); } - public function forCount(): array + public static function forCount(): array { return [ 'zero' => [ diff --git a/Tests/Unit/Domain/Model/Frontend/OpeningHourTest.php b/Tests/Unit/Domain/Model/Frontend/OpeningHourTest.php index 2f896c0..38b91cd 100644 --- a/Tests/Unit/Domain/Model/Frontend/OpeningHourTest.php +++ b/Tests/Unit/Domain/Model/Frontend/OpeningHourTest.php @@ -23,17 +23,13 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Model\Frontend; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use WerkraumMedia\ThueCat\Domain\Model\Frontend\OpeningHour; -/** - * @covers \WerkraumMedia\Domain\Model\Frontend\OpeningHour - */ class OpeningHourTest extends TestCase { - /** - * @test - */ + #[Test] public function returnsReducedOpens(): void { $subject = OpeningHour::createFromArray([ @@ -46,9 +42,7 @@ class OpeningHourTest extends TestCase ); } - /** - * @test - */ + #[Test] public function returnsOpensForEmptyString(): void { $subject = OpeningHour::createFromArray([]); @@ -59,9 +53,7 @@ class OpeningHourTest extends TestCase ); } - /** - * @test - */ + #[Test] public function returnsReducedCloses(): void { $subject = OpeningHour::createFromArray([ @@ -74,9 +66,7 @@ class OpeningHourTest extends TestCase ); } - /** - * @test - */ + #[Test] public function returnsClosesForEmptyString(): void { $subject = OpeningHour::createFromArray([]); @@ -87,9 +77,7 @@ class OpeningHourTest extends TestCase ); } - /** - * @test - */ + #[Test] public function returnsThatThisIsOnlyASingleDay(): void { $subject = OpeningHour::createFromArray([ @@ -108,9 +96,7 @@ class OpeningHourTest extends TestCase self::assertTrue($subject->isSingleDay()); } - /** - * @test - */ + #[Test] public function returnsThatThisIsATimeframe(): void { $subject = OpeningHour::createFromArray([ diff --git a/Tests/Unit/Domain/Model/Frontend/TouristAttractionTest.php b/Tests/Unit/Domain/Model/Frontend/TouristAttractionTest.php index 5159d56..61d99f7 100644 --- a/Tests/Unit/Domain/Model/Frontend/TouristAttractionTest.php +++ b/Tests/Unit/Domain/Model/Frontend/TouristAttractionTest.php @@ -23,6 +23,9 @@ declare(strict_types=1); namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Model\Frontend; +use DateTimeImmutable; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Persistence\ObjectStorage; use WerkraumMedia\ThueCat\Domain\Model\Frontend\MergedOpeningHour; @@ -30,17 +33,11 @@ use WerkraumMedia\ThueCat\Domain\Model\Frontend\MergedOpeningHours; use WerkraumMedia\ThueCat\Domain\Model\Frontend\OpeningHours; use WerkraumMedia\ThueCat\Domain\Model\Frontend\ParkingFacility; use WerkraumMedia\ThueCat\Domain\Model\Frontend\TouristAttraction; -use PHPUnit\Framework\TestCase; use WerkraumMedia\ThueCat\Service\DateBasedFilter; -/** - * @covers \WerkraumMedia\ThueCat\Domain\Model\Frontend\TouristAttraction - */ class TouristAttractionTest extends TestCase { - /** - * @test - */ + #[Test] public function returnsParkingFacilitiesNearBySorted(): void { $unsortedFacilities = new ObjectStorage(); @@ -73,9 +70,7 @@ class TouristAttractionTest extends TestCase return $facility; } - /** - * @test - */ + #[Test] public function returnsDistanceToPublicTransportArrayWithoutTypes(): void { $subject = new TouristAttraction(); @@ -88,9 +83,7 @@ class TouristAttractionTest extends TestCase ], $subject->getDistanceToPublicTransport()); } - /** - * @test - */ + #[Test] public function returnsDistanceToPublicTransportArrayWithTwoTypes(): void { $subject = new TouristAttraction(); @@ -106,12 +99,10 @@ class TouristAttractionTest extends TestCase ], $subject->getDistanceToPublicTransport()); } - /** - * @test - */ + #[Test] public function returnsMergedOpeningHours(): void { - GeneralUtility::addInstance(DateBasedFilter::class, new class implements DateBasedFilter { + GeneralUtility::addInstance(DateBasedFilter::class, new class() implements DateBasedFilter { public function filterOutPreviousDates( array $listToFilter, callable $provideDate @@ -128,10 +119,10 @@ class TouristAttractionTest extends TestCase 'Sunday', ], 'from' => [ - 'date' => '@' . (new \DateTimeImmutable())->format('U'), + 'date' => '@' . (new DateTimeImmutable())->format('U'), ], 'through' => [ - 'date' => '@' . (new \DateTimeImmutable())->modify('+2 days')->format('U'), + 'date' => '@' . (new DateTimeImmutable())->modify('+2 days')->format('U'), ], ], [ @@ -142,10 +133,10 @@ class TouristAttractionTest extends TestCase 'Tuesday', ], 'from' => [ - 'date' => '@' . (new \DateTimeImmutable())->format('U'), + 'date' => '@' . (new DateTimeImmutable())->format('U'), ], 'through' => [ - 'date' => '@' . (new \DateTimeImmutable())->modify('+2 days')->format('U'), + 'date' => '@' . (new DateTimeImmutable())->modify('+2 days')->format('U'), ], ], [ @@ -155,10 +146,10 @@ class TouristAttractionTest extends TestCase 'Saturday', ], 'from' => [ - 'date' => '@' . (new \DateTimeImmutable())->format('U'), + 'date' => '@' . (new DateTimeImmutable())->format('U'), ], 'through' => [ - 'date' => '@' . (new \DateTimeImmutable())->modify('+3 days')->format('U'), + 'date' => '@' . (new DateTimeImmutable())->modify('+3 days')->format('U'), ], ], ]) ?: ''); @@ -171,9 +162,9 @@ class TouristAttractionTest extends TestCase self::assertCount(2, $result); foreach ($result as $index => $mergedHour) { self::assertInstanceOf(MergedOpeningHour::class, $mergedHour); - $today = (new \DateTimeImmutable())->format('Y-m-d'); - $inTwoDays = (new \DateTimeImmutable())->modify('+2 days')->format('Y-m-d'); - $inThreeDays = (new \DateTimeImmutable())->modify('+3 days')->format('Y-m-d'); + $today = (new DateTimeImmutable())->format('Y-m-d'); + $inTwoDays = (new DateTimeImmutable())->modify('+2 days')->format('Y-m-d'); + $inThreeDays = (new DateTimeImmutable())->modify('+3 days')->format('Y-m-d'); if ($index === 0) { self::assertSame($today, $mergedHour->getFrom() ? $mergedHour->getFrom()->format('Y-m-d') : ''); @@ -199,12 +190,10 @@ class TouristAttractionTest extends TestCase } } - /** - * @test - */ + #[Test] public function returnsMergedSpecialOpeningHours(): void { - GeneralUtility::addInstance(DateBasedFilter::class, new class implements DateBasedFilter { + GeneralUtility::addInstance(DateBasedFilter::class, new class() implements DateBasedFilter { public function filterOutPreviousDates( array $listToFilter, callable $provideDate @@ -221,10 +210,10 @@ class TouristAttractionTest extends TestCase 'Sunday', ], 'from' => [ - 'date' => '@' . (new \DateTimeImmutable())->format('U'), + 'date' => '@' . (new DateTimeImmutable())->format('U'), ], 'through' => [ - 'date' => '@' . (new \DateTimeImmutable())->modify('+2 days')->format('U'), + 'date' => '@' . (new DateTimeImmutable())->modify('+2 days')->format('U'), ], ], [ @@ -235,10 +224,10 @@ class TouristAttractionTest extends TestCase 'Tuesday', ], 'from' => [ - 'date' => '@' . (new \DateTimeImmutable())->format('U'), + 'date' => '@' . (new DateTimeImmutable())->format('U'), ], 'through' => [ - 'date' => '@' . (new \DateTimeImmutable())->modify('+2 days')->format('U'), + 'date' => '@' . (new DateTimeImmutable())->modify('+2 days')->format('U'), ], ], [ @@ -248,10 +237,10 @@ class TouristAttractionTest extends TestCase 'Saturday', ], 'from' => [ - 'date' => '@' . (new \DateTimeImmutable())->format('U'), + 'date' => '@' . (new DateTimeImmutable())->format('U'), ], 'through' => [ - 'date' => '@' . (new \DateTimeImmutable())->modify('+3 days')->format('U'), + 'date' => '@' . (new DateTimeImmutable())->modify('+3 days')->format('U'), ], ], ]) ?: ''); @@ -264,9 +253,9 @@ class TouristAttractionTest extends TestCase self::assertCount(2, $result); foreach ($result as $index => $mergedHour) { self::assertInstanceOf(MergedOpeningHour::class, $mergedHour); - $today = (new \DateTimeImmutable())->format('Y-m-d'); - $inTwoDays = (new \DateTimeImmutable())->modify('+2 days')->format('Y-m-d'); - $inThreeDays = (new \DateTimeImmutable())->modify('+3 days')->format('Y-m-d'); + $today = (new DateTimeImmutable())->format('Y-m-d'); + $inTwoDays = (new DateTimeImmutable())->modify('+2 days')->format('Y-m-d'); + $inThreeDays = (new DateTimeImmutable())->modify('+3 days')->format('Y-m-d'); if ($index === 0) { self::assertSame($today, $mergedHour->getFrom() ? $mergedHour->getFrom()->format('Y-m-d') : ''); diff --git a/Tests/Unit/ExtensionTest.php b/Tests/Unit/ExtensionTest.php index 492bc49..ff8d40b 100644 --- a/Tests/Unit/ExtensionTest.php +++ b/Tests/Unit/ExtensionTest.php @@ -23,18 +23,13 @@ namespace WerkraumMedia\ThueCat\Tests\Unit; * 02110-1301, USA. */ +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use WerkraumMedia\ThueCat\Extension; -/** - * @covers \WerkraumMedia\ThueCat\Extension - * @testdox The extension class - */ class ExtensionTest extends TestCase { - /** - * @test - */ + #[Test] public function returnsLanguagePath(): void { self::assertSame('LLL:EXT:thuecat/Resources/Private/Language/', Extension::getLanguagePath()); diff --git a/composer.json b/composer.json index ba129f4..336dd7d 100644 --- a/composer.json +++ b/composer.json @@ -35,42 +35,35 @@ } }, "require": { - "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0", "ext-json": "*", "ext-mbstring": "*", "psr/http-client": "^1.0", "psr/http-factory": "^1.0", - "psr/http-message": "^1.0", - "psr/log": "^1.1", - "symfony/console": "^5.2", - "symfony/dependency-injection": "^5.2", - "symfony/polyfill-php80": "^1.26", - "symfony/property-access": "^5.3", - "symfony/property-info": "^5.3", - "symfony/serializer": "^5.3", - "typo3/cms-backend": "^10.4 || ^11.5", - "typo3/cms-core": "^10.4 || ^11.5", - "typo3/cms-extbase": "^10.4 || ^11.5", - "typo3/cms-frontend": "^10.4 || ^11.5" + "psr/http-message": "^2.0", + "psr/log": "^2.0 || ^3.0", + "symfony/console": "^6.4", + "symfony/dependency-injection": "^6.4", + "symfony/property-access": "^6.4", + "symfony/property-info": "^6.4", + "symfony/serializer": "^6.4", + "typo3/cms-backend": "^12.4", + "typo3/cms-core": "^12.4", + "typo3/cms-extbase": "^12.4", + "typo3/cms-frontend": "^12.4" }, "require-dev": { - "codeception/codeception": "^4.2", - "codeception/module-webdriver": "^2.0", - "jangregor/phpstan-prophecy": "^1.0", + "codappix/typo3-php-datasets": "^1.4", + "codeception/codeception": "^5.0", + "codeception/module-webdriver": "^4.0", + "friendsofphp/php-cs-fixer": "^3.40", "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "1.1.0", - "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^8.5", - "saschaegerer/phpstan-typo3": "^1.1", - "symplify/easy-coding-standard": "^9.0", - "typo3/cms-fluid-styled-content": "^10.4 || ^11.5", - "typo3/testing-framework": "^6.6" - }, - "scripts": { - "post-autoload-dump": [ - "mkdir -p .Build/web/typo3conf/ext/", - "[ -L .Build/web/typo3conf/ext/thuecat ] || ln -snvf ../../../../. .Build/web/typo3conf/ext/thuecat" - ] + "phpstan/phpstan": "1.10.46", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^10.4", + "saschaegerer/phpstan-typo3": "^1.9", + "typo3/cms-fluid-styled-content": "^12.4", + "typo3/testing-framework": "^8.0" }, "config": { "sort-packages": true, @@ -86,9 +79,6 @@ "cms-package-dir": "{$vendor-dir}/typo3/cms", "extension-key": "thuecat", "web-dir": ".Build/web" - }, - "branch-alias": { - "dev-main": "1.1.x-dev" } } } diff --git a/ecs.php b/ecs.php deleted file mode 100644 index 2307d86..0000000 --- a/ecs.php +++ /dev/null @@ -1,64 +0,0 @@ -parameters(); - $services = $containerConfigurator->services(); - - $parameters->set(Option::PATHS, [ - __DIR__ . '/Classes/', - __DIR__ . '/Configuration/', - __DIR__ . '/Tests/', - __DIR__ . '/ecs.php', - __DIR__ . '/ext_emconf.php', - ]); - - $parameters->set(Option::SETS, [ - SetList::PSR_12, - SetList::PHPUNIT, - ]); - - $parameters->set(Option::SKIP, [ - __DIR__ . '/Classes/Domain/Import/EntityMapper/CustomAnnotationExtractor.php', - DeclareStrictTypesFixer::class => [ - __DIR__ . '/Configuration/', - __DIR__ . '/ext_emconf.php', - ], - ]); - - $services->set(DeclareStrictTypesFixer::class); - - $services->set(NoUnusedImportsFixer::class); - $services->set(FullyQualifiedStrictTypesFixer::class); - $services->set(NoMultilineWhitespaceAroundDoubleArrowFixer::class); - $services->set(ArraySyntaxFixer::class)->call('configure', [[ - 'syntax' => 'short', - ]]); - $services->set(SingleQuoteFixer::class); - $services->set(TrailingCommaInMultilineArrayFixer::class); - - $services->set(PhpUnitTestAnnotationFixer::class)->call('configure', [[ - 'style' => 'annotation', - ]]); - $services->set(ClassAttributesSeparationFixer::class)->call('configure', [[ - 'elements' => [ - 'const' => 'one', - 'method' => 'one', - 'property' => 'one', - ], - ]]); -}; diff --git a/ext_emconf.php b/ext_emconf.php index ec918cb..1d92258 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -1,17 +1,16 @@ 'ThüCAT', 'description' => 'Integration of ThüCAT into TYPO3 CMS.', 'category' => 'fe', 'state' => 'stable', - 'uploadfolder' => 0, - 'createDirs' => '', - 'clearCacheOnLoad' => 0, 'author' => 'Daniel Siepmann', 'author_email' => 'coding@daniel-siepmann.de', 'author_company' => '', - 'version' => '2.1.0', + 'version' => '3.0.0', 'constraints' => [ 'depends' => [ 'core' => '', diff --git a/ext_localconf.php b/ext_localconf.php index 5fd4423..537e04f 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -1,13 +1,17 @@ 'crdate', 'expirePeriod' => '180', ]; } -})(\WerkraumMedia\ThueCat\Extension::EXTENSION_KEY); +})(Extension::EXTENSION_KEY); diff --git a/ext_tables.php b/ext_tables.php deleted file mode 100644 index f338cb8..0000000 --- a/ext_tables.php +++ /dev/null @@ -1,5 +0,0 @@ -\\) does not accept array\\.$#" - count: 1 - path: Classes/Domain/Model/Backend/ImportLogEntry.php - - - - message: "#^Property WerkraumMedia\\\\ThueCat\\\\Domain\\\\Model\\\\Backend\\\\ImportLogEntry\\:\\:\\$errorsAsArray \\(array\\\\) does not accept mixed\\.$#" - count: 1 - path: Classes/Domain/Model/Backend/ImportLogEntry.php - - message: "#^Method WerkraumMedia\\\\ThueCat\\\\Domain\\\\Model\\\\Frontend\\\\AccessiblitySpecification\\:\\:getCertificationDeaf\\(\\) should return string but returns mixed\\.$#" count: 1 @@ -244,97 +215,27 @@ parameters: count: 1 path: Classes/Domain/Model/Frontend/OpeningHours.php - - - message: "#^Argument of an invalid type Doctrine\\\\DBAL\\\\Driver\\\\ResultStatement\\|int supplied for foreach, only iterables are supported\\.$#" - count: 1 - path: Classes/Frontend/DataProcessing/ResolveEntities.php - - - - message: "#^Argument of an invalid type Doctrine\\\\DBAL\\\\Result\\|int supplied for foreach, only iterables are supported\\.$#" - count: 1 - path: Classes/Frontend/DataProcessing/ResolveEntities.php - - message: "#^Cannot call method getLanguageOverlay\\(\\) on string\\|TYPO3\\\\CMS\\\\Core\\\\Domain\\\\Repository\\\\PageRepository\\.$#" count: 1 path: Classes/Frontend/DataProcessing/ResolveEntities.php - - message: "#^Right side of \\|\\| is always false\\.$#" + message: "#^Parameter \\#1 \\$className of method TYPO3\\\\CMS\\\\Extbase\\\\Persistence\\\\Generic\\\\Mapper\\\\DataMapper\\:\\:map\\(\\) expects class\\-string\\, string given\\.$#" count: 1 - path: Configuration/TCA/Overrides/pages.php + path: Classes/Frontend/DataProcessing/ResolveEntities.php - - message: "#^Right side of \\|\\| is always false\\.$#" + message: "#^Unable to resolve the template type T in call to method TYPO3\\\\CMS\\\\Extbase\\\\Persistence\\\\Generic\\\\Mapper\\\\DataMapper\\:\\:map\\(\\)$#" count: 1 - path: Configuration/TCA/Overrides/pages_tourist_attraction.php + path: Classes/Frontend/DataProcessing/ResolveEntities.php - - message: "#^Right side of \\|\\| is always false\\.$#" + message: "#^Parameter \\#1 \\$mods of method WerkraumMedia\\\\ThueCat\\\\Updates\\\\BackendModuleUserPermission\\:\\:updateMods\\(\\) expects string, mixed given\\.$#" count: 1 - path: Configuration/TCA/Overrides/sys_template.php + path: Classes/Updates/BackendModuleUserPermission.php - - message: "#^Right side of \\|\\| is always false\\.$#" + message: "#^Method WerkraumMedia\\\\ThueCat\\\\Tests\\\\Acceptance\\\\Support\\\\Environment\\:\\:bootstrapTypo3Environment\\(\\) has no return type specified\\.$#" count: 1 - path: Configuration/TCA/Overrides/tt_content.php - - - - message: "#^Right side of \\|\\| is always false\\.$#" - count: 1 - path: Configuration/TCA/Overrides/tt_content_tourist_attraction.php - - - - message: "#^Right side of \\|\\| is always false\\.$#" - count: 1 - path: Configuration/TCA/tx_thuecat_import_configuration.php - - - - message: "#^Right side of \\|\\| is always false\\.$#" - count: 1 - path: Configuration/TCA/tx_thuecat_import_log.php - - - - message: "#^Right side of \\|\\| is always false\\.$#" - count: 1 - path: Configuration/TCA/tx_thuecat_import_log_entry.php - - - - message: "#^Right side of \\|\\| is always false\\.$#" - count: 1 - path: Configuration/TCA/tx_thuecat_organisation.php - - - - message: "#^Right side of \\|\\| is always false\\.$#" - count: 1 - path: Configuration/TCA/tx_thuecat_parking_facility.php - - - - message: "#^Right side of \\|\\| is always false\\.$#" - count: 1 - path: Configuration/TCA/tx_thuecat_tourist_attraction.php - - - - message: "#^Right side of \\|\\| is always false\\.$#" - count: 1 - path: Configuration/TCA/tx_thuecat_tourist_information.php - - - - message: "#^Right side of \\|\\| is always false\\.$#" - count: 1 - path: Configuration/TCA/tx_thuecat_town.php - - - - message: "#^Cannot call method findByUid\\(\\) on mixed\\.$#" - count: 14 - path: Tests/Functional/ImportTest.php - - - - message: "#^Cannot call method importConfiguration\\(\\) on mixed\\.$#" - count: 14 - path: Tests/Functional/ImportTest.php - - - - message: "#^Parameter \\#2 \\$callback of function usort expects callable\\(TEntity, TEntity\\)\\: int, Closure\\(WerkraumMedia\\\\ThueCat\\\\Domain\\\\Model\\\\Frontend\\\\ParkingFacility, WerkraumMedia\\\\ThueCat\\\\Domain\\\\Model\\\\Frontend\\\\ParkingFacility\\)\\: int\\<\\-1, 1\\> given\\.$#" - count: 1 - path: Classes/Domain/Model/Frontend/Place.php + path: Tests/Acceptance/Support/Environment.php diff --git a/phpstan.neon b/phpstan.neon index 5df3728..bef4063 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -10,13 +10,5 @@ parameters: - Tests/Acceptance/Support/_generated/ - Classes/Domain/Import/EntityMapper/CustomAnnotationExtractor.php checkMissingIterableValueType: false - reportUnmatchedIgnoredErrors: false + reportUnmatchedIgnoredErrors: true checkGenericClassInNonGenericObjectType: false - ignoreErrors: - # Depending on TYPO3 version - - "#^Argument of an invalid type Doctrine\\\\DBAL\\\\Driver\\\\ResultStatement\\|int supplied for foreach, only iterables are supported\\.$#" - - "#^Argument of an invalid type Doctrine\\\\DBAL\\\\Result\\|int supplied for foreach, only iterables are supported\\.$#" - - "#^Cannot call method fetchColumn\\(\\) on Doctrine\\\\DBAL\\\\Driver\\\\ResultStatement\\|int\\.$#" - - "#^Cannot call method fetchColumn\\(\\) on Doctrine\\\\DBAL\\\\Result\\|int\\.$#" - - "#^Cannot call method fetchOne\\(\\) on Doctrine\\\\DBAL\\\\Driver\\\\ResultStatement\\|int\\.$#" - - "#^Cannot call method fetchOne\\(\\) on Doctrine\\\\DBAL\\\\Result\\|int\\.$#" diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 4d4f27c..95cb5b7 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,22 +1,27 @@ + cacheDirectory=".phpunit.cache" + backupStaticProperties="false" + requireCoverageMetadata="false" + beStrictAboutCoverageMetadata="false" +> + + + Classes + + + + @@ -27,12 +32,6 @@ - - - Classes - - - diff --git a/shell.nix b/shell.nix index 613b42c..9ca6aee 100644 --- a/shell.nix +++ b/shell.nix @@ -24,6 +24,31 @@ let composer update --prefer-dist --no-progress --working-dir="$PROJECT_ROOT" ''; }; + + projectCgl = pkgs.writeShellApplication { + name = "project-cgl"; + + runtimeInputs = [ + php + ]; + + text = '' + PHP_CS_FIXER_IGNORE_ENV=1 ./vendor/bin/php-cs-fixer fix --dry-run --diff + ''; + }; + + projectCglFix = pkgs.writeShellApplication { + name = "project-cgl-fix"; + + runtimeInputs = [ + php + ]; + + text = '' + PHP_CS_FIXER_IGNORE_ENV=1 ./vendor/bin/php-cs-fixer fix + ''; + }; + projectTestAcceptance = pkgs.writeShellApplication { name = "project-test-acceptance"; runtimeInputs = [ @@ -50,6 +75,8 @@ in pkgs.mkShell { php composer projectInstall + projectCgl + projectCglFix projectTestAcceptance ];