diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..578dc10d --- /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 3f85f7b3..2ade17ba 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 51313d02..16c3c4b9 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 00000000..5bd6dc42 --- /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 95e4dad2..c8b1630f 100644 --- a/Classes/Command/ImportConfigurationCommand.php +++ b/Classes/Command/ImportConfigurationCommand.php @@ -34,24 +34,11 @@ 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 489e8624..fe4ed3cd 100644 --- a/Classes/Controller/Backend/AbstractController.php +++ b/Classes/Controller/Backend/AbstractController.php @@ -23,22 +23,30 @@ 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; - - /** - * Backend Template Container - * - * @var string - */ - protected $defaultViewObjectName = BackendTemplateView::class; + private ModuleTemplateFactory $moduleTemplateFactory; + + 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 91e18476..18dfc38a 100644 --- a/Classes/Controller/Backend/ConfigurationController.php +++ b/Classes/Controller/Backend/ConfigurationController.php @@ -23,34 +23,25 @@ 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 09f20dc5..396eefba 100644 --- a/Classes/Controller/Backend/ImportController.php +++ b/Classes/Controller/Backend/ImportController.php @@ -23,8 +23,9 @@ 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 @@ 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 @@ public function importAction(ImportConfiguration $importConfiguration): void $this->createImportDoneFlashMessage($importConfiguration); } - $this->redirect('index', 'Backend\Configuration'); + return $this->redirect('index', 'Backend\Configuration'); } private function createImportErrorFlashMessage(ImportConfiguration $importConfiguration): void @@ -93,7 +76,7 @@ private function createImportErrorFlashMessage(ImportConfiguration $importConfig 'controller.backend.import.import.error.title', Extension::EXTENSION_NAME ), - AbstractMessage::ERROR + ContextualFeedbackSeverity::ERROR ); } @@ -109,7 +92,7 @@ private function createImportDoneFlashMessage(ImportConfiguration $importConfigu '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 a07eaf44..d2356e84 100644 --- a/Classes/DependencyInjection/ConverterPass.php +++ b/Classes/DependencyInjection/ConverterPass.php @@ -29,7 +29,7 @@ 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 8bff4b6f..34288bd5 100644 --- a/Classes/DependencyInjection/EntityPass.php +++ b/Classes/DependencyInjection/EntityPass.php @@ -29,7 +29,7 @@ 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 0edd3b23..ba6473c6 100644 --- a/Classes/DependencyInjection/UrlProvidersPass.php +++ b/Classes/DependencyInjection/UrlProvidersPass.php @@ -29,7 +29,7 @@ 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 16f790de..761e7dd1 100644 --- a/Classes/Domain/Import/Entity/AccessibilityCertification.php +++ b/Classes/Domain/Import/Entity/AccessibilityCertification.php @@ -27,45 +27,21 @@ 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 @@ public function getCertificationAccessibilityWheelchair(): string /** * @internal for mapping via Symfony component. + * * @param string|array $accessibilityCertificationStatus */ public function setAccessibilityCertificationStatus($accessibilityCertificationStatus): void @@ -121,6 +98,7 @@ public function setAccessibilityCertificationStatus($accessibilityCertificationS /** * @internal for mapping via Symfony component. + * * @param string|array $certificationAccessibilityDeaf */ public function setCertificationAccessibilityDeaf($certificationAccessibilityDeaf): void @@ -133,6 +111,7 @@ public function setCertificationAccessibilityDeaf($certificationAccessibilityDea /** * @internal for mapping via Symfony component. + * * @param string|array $certificationAccessibilityMental */ public function setCertificationAccessibilityMental($certificationAccessibilityMental): void @@ -145,6 +124,7 @@ public function setCertificationAccessibilityMental($certificationAccessibilityM /** * @internal for mapping via Symfony component. + * * @param string|array $certificationAccessibilityPartiallyDeaf */ public function setCertificationAccessibilityPartiallyDeaf($certificationAccessibilityPartiallyDeaf): void @@ -157,6 +137,7 @@ public function setCertificationAccessibilityPartiallyDeaf($certificationAccessi /** * @internal for mapping via Symfony component. + * * @param string|array $certificationAccessibilityPartiallyVisual */ public function setCertificationAccessibilityPartiallyVisual($certificationAccessibilityPartiallyVisual): void @@ -169,6 +150,7 @@ public function setCertificationAccessibilityPartiallyVisual($certificationAcces /** * @internal for mapping via Symfony component. + * * @param string|array $certificationAccessibilityVisual */ public function setCertificationAccessibilityVisual($certificationAccessibilityVisual): void @@ -181,6 +163,7 @@ public function setCertificationAccessibilityVisual($certificationAccessibilityV /** * @internal for mapping via Symfony component. + * * @param string|array $certificationAccessibilityWalking */ public function setCertificationAccessibilityWalking($certificationAccessibilityWalking): void @@ -193,6 +176,7 @@ public function setCertificationAccessibilityWalking($certificationAccessibility /** * @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 8f788d9d..68ca3bd9 100644 --- a/Classes/Domain/Import/Entity/AccessibilitySpecification.php +++ b/Classes/Domain/Import/Entity/AccessibilitySpecification.php @@ -27,45 +27,21 @@ 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 6bd88a4d..3efcba11 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 @@ public function setPhoto(ForeignReference $photo): void /** * @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 c65c57ae..e3301fd7 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 aaf6ebcd..7026acff 100644 --- a/Classes/Domain/Import/Entity/MediaObject.php +++ b/Classes/Domain/Import/Entity/MediaObject.php @@ -27,30 +27,18 @@ 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 @@ public function getType(): string */ public function setCopyrightYear(string $copyrightYear): void { - $this->copyrightYear = (int) $copyrightYear; + $this->copyrightYear = (int)$copyrightYear; } /** @@ -106,6 +94,7 @@ public function setLicenseAuthor(string $licenseAuthor): void /** * @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 32dc453a..b8424d9d 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 @@ public function setDescription(string $description): void /** * @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 d30c2fbd..4bb692e8 100644 --- a/Classes/Domain/Import/Entity/Person.php +++ b/Classes/Domain/Import/Entity/Person.php @@ -25,15 +25,9 @@ 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 208e10ad..4f677674 100644 --- a/Classes/Domain/Import/Entity/Place.php +++ b/Classes/Domain/Import/Entity/Place.php @@ -23,14 +23,15 @@ 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 @@ public function getOpeningHoursSpecification(): array return GeneralUtility::makeInstance(DateBasedFilter::class) ->filterOutPreviousDates( $this->openingHoursSpecifications, - function (OpeningHour $hour): ?\DateTimeImmutable { + function (OpeningHour $hour): ?DateTimeImmutable { return $hour->getValidThrough(); } - ); + ) + ; } /** @@ -175,10 +165,11 @@ public function getSpecialOpeningHoursSpecification(): array return GeneralUtility::makeInstance(DateBasedFilter::class) ->filterOutPreviousDates( $this->specialOpeningHours, - function (OpeningHour $hour): ?\DateTimeImmutable { + function (OpeningHour $hour): ?DateTimeImmutable { return $hour->getValidThrough(); } - ); + ) + ; } /** @@ -252,6 +243,7 @@ public function removeParkingFacilityNearBy(ForeignReference $parkingFacilityNea /** * @internal for mapping via Symfony component. + * * @param string|array $sanitation */ public function setSanitation($sanitation): void @@ -265,6 +257,7 @@ public function setSanitation($sanitation): void /** * @internal for mapping via Symfony component. + * * @param string|array $otherService */ public function setOtherService($otherService): void @@ -278,6 +271,7 @@ public function setOtherService($otherService): void /** * @internal for mapping via Symfony component. + * * @param string|array $trafficInfrastructure */ public function setTrafficInfrastructure($trafficInfrastructure): void @@ -291,6 +285,7 @@ public function setTrafficInfrastructure($trafficInfrastructure): void /** * @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 0776e5d0..587c4bc8 100644 --- a/Classes/Domain/Import/Entity/Properties/Address.php +++ b/Classes/Domain/Import/Entity/Properties/Address.php @@ -25,35 +25,17 @@ 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 0055df48..cd577ddd 100644 --- a/Classes/Domain/Import/Entity/Properties/DayOfWeek.php +++ b/Classes/Domain/Import/Entity/Properties/DayOfWeek.php @@ -25,14 +25,8 @@ 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 5b48af39..e6fa2bcd 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 275dcbaa..4cbc5878 100644 --- a/Classes/Domain/Import/Entity/Properties/Geo.php +++ b/Classes/Domain/Import/Entity/Properties/Geo.php @@ -25,15 +25,9 @@ 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 @@ public function getLatitude(): float */ public function setLongitude(string $longitude): void { - $this->longitude = (float) $longitude; + $this->longitude = (float)$longitude; } /** @@ -58,6 +52,6 @@ public function setLongitude(string $longitude): void */ 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 0592126b..8367f23d 100644 --- a/Classes/Domain/Import/Entity/Properties/Offer.php +++ b/Classes/Domain/Import/Entity/Properties/Offer.php @@ -23,20 +23,20 @@ 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 @@ public function getOfferTypes(): array /** * @internal for mapping via Symfony component. + * * @param string|array $offerType */ public function setOfferType($offerType): void @@ -57,7 +58,7 @@ public function setOfferType($offerType): void } $this->offerTypes = array_map( - [PropertyValues::class, 'removePrefixFromEntry'], + PropertyValues::removePrefixFromEntry(...), $offerType ); } @@ -72,6 +73,7 @@ public function getPrices(): array /** * @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 357da021..99b5d60e 100644 --- a/Classes/Domain/Import/Entity/Properties/OpeningHour.php +++ b/Classes/Domain/Import/Entity/Properties/OpeningHour.php @@ -23,49 +23,39 @@ 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 @@ public function getDaysOfWeek(): array /** * @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 @@ public function setValidFrom(\DateTimeImmutable $validFrom): void /** * @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 @@ public function setValidThrough(\DateTimeImmutable $validThrough): void /** * @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 @@ public function setOpens(\DateTimeImmutable $opens): void /** * @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 6d93ee84..3d6617fb 100644 --- a/Classes/Domain/Import/Entity/Properties/PriceSpecification.php +++ b/Classes/Domain/Import/Entity/Properties/PriceSpecification.php @@ -23,31 +23,24 @@ 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 @@ public function setPriceCurrency(string $currency): void /** * @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 95929d1c..a7605890 100644 --- a/Classes/Domain/Import/Entity/Shared/ContainedInPlace.php +++ b/Classes/Domain/Import/Entity/Shared/ContainedInPlace.php @@ -42,6 +42,7 @@ public function getContainedInPlaces(): array /** * @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 e12de9a5..50115f2e 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 bfd1710d..62e20472 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 @@ public function getOffers(): array /** * @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 fd2579ad..0e6648dd 100644 --- a/Classes/Domain/Import/Entity/TouristAttraction.php +++ b/Classes/Domain/Import/Entity/TouristAttraction.php @@ -27,55 +27,40 @@ 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 @@ public function setStartOfConstruction(string $startOfConstruction): void /** * @internal for mapping via Symfony component. + * * @param string|array $museumService */ public function setMuseumService($museumService): void @@ -173,6 +159,7 @@ public function setMuseumService($museumService): void /** * @internal for mapping via Symfony component. + * * @param string|array $architecturalStyle */ public function setArchitecturalStyle($architecturalStyle): void @@ -186,6 +173,7 @@ public function setArchitecturalStyle($architecturalStyle): void /** * @internal for mapping via Symfony component. + * * @param string|array $digitalOffer */ public function setDigitalOffer($digitalOffer): void @@ -199,6 +187,7 @@ public function setDigitalOffer($digitalOffer): void /** * @internal for mapping via Symfony component. + * * @param string|array $photography */ public function setPhotography($photography): void @@ -236,6 +225,7 @@ public function setPublicAccess(string $publicAccess): void /** * @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 d82fed2a..5fe5a9f1 100644 --- a/Classes/Domain/Import/EntityMapper.php +++ b/Classes/Domain/Import/EntityMapper.php @@ -30,6 +30,7 @@ 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 @@ public function mapDataToEntity( 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 282d0ec0..936b6fa5 100644 --- a/Classes/Domain/Import/EntityMapper/CustomAnnotationExtractor.php +++ b/Classes/Domain/Import/EntityMapper/CustomAnnotationExtractor.php @@ -23,13 +23,21 @@ 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 @@ */ 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 @@ public function getLongDescription(string $class, string $property, array $conte $contents = $docBlock->getDescription()->render(); - return '' === $contents ? null : $contents; + return $contents === '' ? null : $contents; } /** @@ -161,7 +169,7 @@ public function getTypes(string $class, string $property, array $context = []): $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 @@ public function getTypes(string $class, string $property, array $context = []): return null; } - if (!\in_array($prefix, $this->arrayMutatorPrefixes)) { + if (!in_array($prefix, $this->arrayMutatorPrefixes)) { return $types; } @@ -210,12 +218,12 @@ public function getTypesFromConstructor(string $class, string $property): ?array $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 @@ public function getTypesFromConstructor(string $class, string $property): ?array 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 @@ private function getDocBlockFromConstructor(string $class, string $property): ?D $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 @@ private function getDocBlockFromConstructor(string $class, string $property): ?D 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 @@ private function getDocBlockFromProperty(string $class, string $property): ?DocB { // 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 @@ private function getDocBlockFromProperty(string $class, string $property): ?DocB try { return $this->docBlockFactory->create($reflectionProperty, $this->createFromReflector($reflector)); - } catch (\InvalidArgumentException|\RuntimeException $e) { + } catch (InvalidArgumentException|RuntimeException) { return null; } } @@ -315,25 +330,25 @@ private function getDocBlockFromProperty(string $class, string $property): ?DocB */ 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 @@ private function getDocBlockFromMethod(string $class, string $ucFirstProperty, i try { return [$this->docBlockFactory->create($reflectionMethod, $this->createFromReflector($reflector)), $prefix]; - } catch (\InvalidArgumentException|\RuntimeException $e) { + } catch (InvalidArgumentException|RuntimeException) { return null; } } @@ -360,9 +375,9 @@ private function getDocBlockFromMethod(string $class, string $ucFirstProperty, i /** * 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 ad94dfbe..3c545666 100644 --- a/Classes/Domain/Import/EntityMapper/EntityRegistry.php +++ b/Classes/Domain/Import/EntityMapper/EntityRegistry.php @@ -23,9 +23,6 @@ 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 @@ public function getEntityByTypes(array $types): string 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 29c53f9d..4e0c5181 100644 --- a/Classes/Domain/Import/EntityMapper/JsonDecode.php +++ b/Classes/Domain/Import/EntityMapper/JsonDecode.php @@ -23,9 +23,8 @@ 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 @@ */ 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 @@ public function decode( 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 @@ private function process( * * 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 @@ private function decodeLanguageSpecificValue( * * 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 @@ private function decodeSingleValues( /** * Prepare data structure for PHP \DateTimeImmutable. * - * @param mixed $value + * * @return mixed */ private function decodeDateTime( - &$value + mixed &$value ) { $supportedTypes = [ 'schema:Time', @@ -213,22 +211,21 @@ private function decodeDateTime( } /** - * @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 @@ private function mapKey($key) 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 035860a7..eb520a40 100644 --- a/Classes/Domain/Import/EntityMapper/MappingException.php +++ b/Classes/Domain/Import/EntityMapper/MappingException.php @@ -23,30 +23,21 @@ namespace WerkraumMedia\ThueCat\Domain\Import\EntityMapper; -class MappingException extends \Exception -{ - /** - * @var array - */ - protected $jsonLD = []; - - /** - * @var string - */ - protected $targetClassName = ''; +use Exception; +use Throwable; +class MappingException extends Exception +{ 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 fb4969cf..48885ef3 100644 --- a/Classes/Domain/Import/EntityMapper/PropertyValues.php +++ b/Classes/Domain/Import/EntityMapper/PropertyValues.php @@ -36,7 +36,7 @@ public static function removePrefixFromEntry(string $entryWithPrefix): string 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 1311897c..5923ce12 100644 --- a/Classes/Domain/Import/Import.php +++ b/Classes/Domain/Import/Import.php @@ -23,6 +23,7 @@ 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 e67f0563..b8a650a5 100644 --- a/Classes/Domain/Import/Importer.php +++ b/Classes/Domain/Import/Importer.php @@ -23,12 +23,13 @@ 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 @@ class Importer { - /** - * @var UrlProviderRegistry - */ - private $urls; - - /** - * @var Converter - */ - private $converter; - - /** - * @var EntityRegistry - */ - private $entityRegistry; - - /** - * @var EntityMapper - */ - private $entityMapper; + private readonly Logger $logger; - /** - * @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 @@ private function import(): void { $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 @@ private function importJsonEntity(array $jsonEntity, string $url): void } 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 @@ private function importJsonEntity(array $jsonEntity, string $url): void '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 5d5b2a0f..544d3f82 100644 --- a/Classes/Domain/Import/Importer/FetchData.php +++ b/Classes/Domain/Import/Importer/FetchData.php @@ -32,39 +32,15 @@ class FetchData { - /** - * @var RequestFactoryInterface - */ - private $requestFactory; - - /** - * @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 $databaseUrlPrefix = 'https://cdb.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 @@ public function jsonLDFromUrl(string $url): array $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 4568a56c..b51528ca 100644 --- a/Classes/Domain/Import/Importer/FetchData/InvalidResponseException.php +++ b/Classes/Domain/Import/Importer/FetchData/InvalidResponseException.php @@ -23,6 +23,8 @@ 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 ac126131..10a7a640 100644 --- a/Classes/Domain/Import/Importer/SaveData.php +++ b/Classes/Domain/Import/Importer/SaveData.php @@ -33,26 +33,14 @@ 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 @@ private function updateKnownData(EntityCollection $entities): void $identifier = $this->getIdentifier($entity); if (is_numeric($identifier)) { - $entity->setExistingTypo3Uid((int) $identifier); + $entity->setExistingTypo3Uid((int)$identifier); } } } @@ -155,7 +143,7 @@ private function getIdentifier(Entity $entity): string $existingUid = $this->getExistingUid($entity); if ($existingUid > 0) { - return (string) $existingUid; + return (string)$existingUid; } $identifier = 'NEW_' . sha1($entity->getRemoteId() . $entity->getTypo3SystemLanguageUid()); @@ -176,7 +164,8 @@ private function getExistingUid(Entity $entity): int $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 @@ private function getExistingUid(Entity $entity): int )); } - $result = $queryBuilder->execute()->fetchColumn(); + $result = $queryBuilder->executeQuery()->fetchOne(); if (is_numeric($result)) { - return (int) $result; + return (int)$result; } return 0; @@ -216,9 +205,9 @@ private function getDefaultLanguageIdentifier(Entity $entity): int $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 f383c724..efad8805 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 @@ public function getEntitiesToTranslate(): array { 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 30460458..534fa993 100644 --- a/Classes/Domain/Import/Model/GenericEntity.php +++ b/Classes/Domain/Import/Model/GenericEntity.php @@ -25,53 +25,20 @@ class GenericEntity implements Entity { - /** - * @var int - */ - private $typo3StoragePid; + private bool $created = false; - /** - * @var string - */ - private $typo3DatabaseTableName; + private int $typo3Uid = 0; /** - * @var int + * @param mixed[] $data */ - 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 2e9302df..bfba08a8 100644 --- a/Classes/Domain/Import/RequestFactory.php +++ b/Classes/Domain/Import/RequestFactory.php @@ -32,29 +32,11 @@ 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 @@ public function __construct( 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 @@ public function createRequest(string $method, $uri): RequestInterface 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 cbd7b91f..8f1aeaa6 100644 --- a/Classes/Domain/Import/ResolveForeignReference.php +++ b/Classes/Domain/Import/ResolveForeignReference.php @@ -23,9 +23,9 @@ 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 @@ */ 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 @@ public function resolve( ): ?object { try { $jsonLD = $this->fetchData->jsonLDFromUrl($foreignReference->getId()); - } catch (InvalidResponseException $e) { + } catch (InvalidResponseException) { return null; } @@ -94,6 +76,7 @@ public function resolve( /** * @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 d5719f35..eb98011c 100644 --- a/Classes/Domain/Import/Typo3Converter.php +++ b/Classes/Domain/Import/Typo3Converter.php @@ -23,6 +23,8 @@ 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 @@ 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 @@ public function convert( 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 40613cbc..4454dc4b 100644 --- a/Classes/Domain/Import/Typo3Converter/GeneralConverter.php +++ b/Classes/Domain/Import/Typo3Converter/GeneralConverter.php @@ -23,8 +23,9 @@ 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 @@ class GeneralConverter implements Converter { - /** - * @var ResolveForeignReference - */ - private $resolveForeignReference; - - /** - * @var Importer - */ - private $importer; - - /** - * @var LanguageHandling - */ - private $languageHandling; - - /** - * @var OrganisationRepository - */ - private $organisationRepository; - - /** - * @var TownRepository - */ - private $townRepository; - - /** - * @var ParkingFacilityRepository - */ - private $parkingFacilityRepository; - - /** - * @var NameExtractor - */ - private $nameExtractor; + private readonly Logger $logger; - /** - * @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 @@ public function convert( $converted = new GenericEntity( $importConfiguration->getStoragePid(), - $this->getTableNameByEntityClass(get_class($entity)), + $this->getTableNameByEntityClass($entity::class), $this->languageHandling->getLanguageUidForString( $importConfiguration->getStoragePid(), $language @@ -167,12 +120,12 @@ private function shouldConvert( 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 @@ private function getTableNameByEntityClass(string $className): string { $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 @@ private function getTownUid(object $entity): string ) ); $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 @@ private function getAccessibilitySpecification( if ($result === false || $result === '[]') { return '{}'; } + return $result; } @@ -393,7 +347,7 @@ private function getMedia( } } - return json_encode($data) ?: ''; + return json_encode($data, JSON_THROW_ON_ERROR) ?: ''; } private function getSingleMedia( @@ -433,7 +387,7 @@ private function getOpeningHours(array $openingHours): string ]); } - return json_encode($data) ?: ''; + return json_encode($data, JSON_THROW_ON_ERROR) ?: ''; } private function getAddress(Place $entity): string @@ -462,7 +416,7 @@ private function getAddress(Place $entity): string ]; } - return json_encode($data) ?: ''; + return json_encode($data, JSON_THROW_ON_ERROR) ?: ''; } private function getOffers(Place $entity): string @@ -473,11 +427,11 @@ private function getOffers(Place $entity): string '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 9b024d63..d80afbbd 100644 --- a/Classes/Domain/Import/Typo3Converter/LanguageHandling.php +++ b/Classes/Domain/Import/Typo3Converter/LanguageHandling.php @@ -23,6 +23,7 @@ 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 @@ 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 f87ae6d1..85fdc24b 100644 --- a/Classes/Domain/Import/Typo3Converter/NameExtractor.php +++ b/Classes/Domain/Import/Typo3Converter/NameExtractor.php @@ -28,15 +28,9 @@ class NameExtractor { - /** - * @var ResolveForeignReference - */ - private $resolveForeignReference; - public function __construct( - ResolveForeignReference $resolveForeignReference + private readonly ResolveForeignReference $resolveForeignReference ) { - $this->resolveForeignReference = $resolveForeignReference; } /** @@ -65,7 +59,7 @@ public function extract( } 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 2b038e23..33b147c3 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 8f0c7529..af4016fc 100644 --- a/Classes/Domain/Import/UrlProvider/ContainsPlaceUrlProvider.php +++ b/Classes/Domain/Import/UrlProvider/ContainsPlaceUrlProvider.php @@ -23,25 +23,17 @@ 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 @@ public function createWithConfiguration( 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 6595f5fc..3fb0740f 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 5b3b8363..e907c7b8 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 6afa5e4b..7b4d8272 100644 --- a/Classes/Domain/Import/UrlProvider/SyncScopeUrlProvider.php +++ b/Classes/Domain/Import/UrlProvider/SyncScopeUrlProvider.php @@ -23,25 +23,17 @@ 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 @@ public function createWithConfiguration( 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 c5c677b7..c4e7e8e6 100644 --- a/Classes/Domain/Model/Backend/AbstractEntity.php +++ b/Classes/Domain/Model/Backend/AbstractEntity.php @@ -23,29 +23,18 @@ 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 @@ public function getDescription(): string 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 86113b93..895a4724 100644 --- a/Classes/Domain/Model/Backend/ImportConfiguration.php +++ b/Classes/Domain/Model/Backend/ImportConfiguration.php @@ -23,6 +23,8 @@ 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 @@ 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 @@ public function getTableName(): string 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 @@ public function getStoragePid(): int $storagePid = $this->getConfigurationValueFromFlexForm('storagePid'); if (is_numeric($storagePid) && $storagePid > 0) { - return intval($storagePid); + return (int)$storagePid; } return 0; @@ -151,7 +141,7 @@ public function getContainsPlaceId(): string { $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 ca094b8e..b4e14be2 100644 --- a/Classes/Domain/Model/Backend/ImportLog.php +++ b/Classes/Domain/Model/Backend/ImportLog.php @@ -23,6 +23,7 @@ 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 @@ public function getEntries(): ObjectStorage 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 12db1d36..ef13af66 100644 --- a/Classes/Domain/Model/Backend/ImportLogEntry/MappingError.php +++ b/Classes/Domain/Model/Backend/ImportLogEntry/MappingError.php @@ -23,26 +23,26 @@ 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 @@ public function getErrors(): array { $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 4b615970..2ef6ecb1 100644 --- a/Classes/Domain/Model/Backend/ImportLogEntry/SavingEntity.php +++ b/Classes/Domain/Model/Backend/ImportLogEntry/SavingEntity.php @@ -23,56 +23,42 @@ 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 @@ public function getRecordDatabaseTableName(): string 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 @@ public function getType(): string 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 0064d106..05d359cf 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 f41723c2..4799b8db 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 8c78802f..e83728e2 100644 --- a/Classes/Domain/Model/Frontend/AccessiblitySpecification.php +++ b/Classes/Domain/Model/Frontend/AccessiblitySpecification.php @@ -27,19 +27,14 @@ 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 b29dbb48..5e08c155 100644 --- a/Classes/Domain/Model/Frontend/Address.php +++ b/Classes/Domain/Model/Frontend/Address.php @@ -27,20 +27,15 @@ 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 985c4157..02bfc2f1 100644 --- a/Classes/Domain/Model/Frontend/Base.php +++ b/Classes/Domain/Model/Frontend/Base.php @@ -27,20 +27,11 @@ abstract class Base extends AbstractEntity { - /** - * @var string - */ - protected $title = ''; - - /** - * @var string - */ - protected $description = ''; - - /** - * @var Media|null - */ - protected $media = null; + protected string $title = ''; + + protected string $description = ''; + + 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 028e6c2a..8c825220 100644 --- a/Classes/Domain/Model/Frontend/Media.php +++ b/Classes/Domain/Model/Frontend/Media.php @@ -28,24 +28,19 @@ 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 @@ public function getEditorialImages(): array /** * @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 6ab91717..69585112 100644 --- a/Classes/Domain/Model/Frontend/MergedOpeningHour.php +++ b/Classes/Domain/Model/Frontend/MergedOpeningHour.php @@ -23,27 +23,23 @@ 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 @@ public function getWeekDaysWithMondayFirstWeekDay(): array ]); } - 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 ad92c6cb..814aa9c4 100644 --- a/Classes/Domain/Model/Frontend/MergedOpeningHourWeekDay.php +++ b/Classes/Domain/Model/Frontend/MergedOpeningHourWeekDay.php @@ -27,29 +27,11 @@ 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 b93fff45..26cb3a1a 100644 --- a/Classes/Domain/Model/Frontend/MergedOpeningHours.php +++ b/Classes/Domain/Model/Frontend/MergedOpeningHours.php @@ -23,17 +23,17 @@ 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 73a42b11..5052c48e 100644 --- a/Classes/Domain/Model/Frontend/Offer.php +++ b/Classes/Domain/Model/Frontend/Offer.php @@ -27,45 +27,19 @@ 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 @@ public function getTitle(): string 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 9821edfa..17a37657 100644 --- a/Classes/Domain/Model/Frontend/Offers.php +++ b/Classes/Domain/Model/Frontend/Offers.php @@ -23,31 +23,25 @@ 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 5b03f321..3951979b 100644 --- a/Classes/Domain/Model/Frontend/OpeningHour.php +++ b/Classes/Domain/Model/Frontend/OpeningHour.php @@ -23,63 +23,35 @@ 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 @@ public function getDaysOfWeekWithMondayFirstWeekDay(): array ]); } - 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 @@ public function isSingleDay(): bool $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 ed51800a..6b07adbd 100644 --- a/Classes/Domain/Model/Frontend/OpeningHours.php +++ b/Classes/Domain/Model/Frontend/OpeningHours.php @@ -23,33 +23,28 @@ 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 @@ private function createArray(string $serialized): array $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 46a0f22a..3b79474a 100644 --- a/Classes/Domain/Model/Frontend/Place.php +++ b/Classes/Domain/Model/Frontend/Place.php @@ -28,60 +28,45 @@ 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 = ''; - /** - * @var string - */ - protected $otherService = ''; + protected string $otherService = ''; - /** - * @var string - */ - protected $trafficInfrastructure = ''; + protected string $trafficInfrastructure = ''; /** + * Necessary for Extbase/Symfony. + * * @var string */ - protected $paymentAccepted = ''; + protected string $paymentAccepted = ''; /** + * Necessary for Extbase/Symfony. + * * @var string */ - protected $distanceToPublicTransport = ''; + protected string $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 795972ac..95238cee 100644 --- a/Classes/Domain/Model/Frontend/Price.php +++ b/Classes/Domain/Model/Frontend/Price.php @@ -27,43 +27,13 @@ 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 1f3f169c..7a85f42d 100644 --- a/Classes/Domain/Model/Frontend/TouristAttraction.php +++ b/Classes/Domain/Model/Frontend/TouristAttraction.php @@ -27,60 +27,37 @@ class TouristAttraction extends Place { - /** - * @var string - */ - protected $slogan = ''; + protected string $slogan = ''; - /** - * @var Offers|null - */ - protected $offers = null; + protected ?Offers $offers = null; - /** - * @var Town|null - */ - protected $town = null; + protected ?Town $town = null; - /** - * @var string - */ - protected $startOfConstruction = ''; + protected string $startOfConstruction = ''; - /** - * @var string - */ - protected $museumService = ''; + protected string $museumService = ''; - /** - * @var string - */ - protected $architecturalStyle = ''; + protected string $architecturalStyle = ''; /** + * Necessary for Extbase/Symfony. + * * @var string */ - protected $digitalOffer = ''; + protected string $digitalOffer = ''; /** + * Necessary for Extbase/Symfony. + * * @var string */ - protected $photography = ''; + protected string $photography = ''; - /** - * @var string - */ - protected $petsAllowed = ''; + protected string $petsAllowed = ''; - /** - * @var string - */ - protected $isAccessibleForFree = ''; + protected string $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 f19354b3..34a2b4f1 100644 --- a/Classes/Domain/Repository/Backend/ImportConfigurationRepository.php +++ b/Classes/Domain/Repository/Backend/ImportConfigurationRepository.php @@ -23,7 +23,6 @@ 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 @@ 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 a4fa8e9a..84122778 100644 --- a/Classes/Domain/Repository/Backend/ImportLogRepository.php +++ b/Classes/Domain/Repository/Backend/ImportLogRepository.php @@ -24,7 +24,6 @@ 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 @@ 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 @@ private function getLogEntries(ImportLog $log): array '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 29c21d35..446cb6c5 100644 --- a/Classes/Domain/Repository/Backend/OrganisationRepository.php +++ b/Classes/Domain/Repository/Backend/OrganisationRepository.php @@ -23,7 +23,6 @@ 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 @@ 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 45e9d234..1037b505 100644 --- a/Classes/Domain/Repository/Backend/ParkingFacilityRepository.php +++ b/Classes/Domain/Repository/Backend/ParkingFacilityRepository.php @@ -23,7 +23,6 @@ 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 @@ 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 7c475170..52e0d1fa 100644 --- a/Classes/Domain/Repository/Backend/TownRepository.php +++ b/Classes/Domain/Repository/Backend/TownRepository.php @@ -23,7 +23,6 @@ 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 @@ 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 382011d6..7e1edd8c 100644 --- a/Classes/Extension.php +++ b/Classes/Extension.php @@ -24,80 +24,30 @@ 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 @@ private static function addContentElements(): void 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 2ae37d0f..3d7797af 100644 --- a/Classes/Frontend/DataProcessing/ResolveEntities.php +++ b/Classes/Frontend/DataProcessing/ResolveEntities.php @@ -33,27 +33,12 @@ 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 @@ public function process( 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 @@ private function resolveEntities(string $tableName, array $uids): array )); $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 1671cb7b..24b4a2af 100644 --- a/Classes/Service/DateBasedFilter/FilterBasedOnTypo3Context.php +++ b/Classes/Service/DateBasedFilter/FilterBasedOnTypo3Context.php @@ -23,20 +23,15 @@ 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 @@ public function filterOutPreviousDates( 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 e977729a..a182ca05 100644 --- a/Classes/Typo3/Extbase/DataMapping/AfterObjectThawedHandler.php +++ b/Classes/Typo3/Extbase/DataMapping/AfterObjectThawedHandler.php @@ -36,22 +36,10 @@ */ 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 @@ private function attachEditorialImages(Base $object): void 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 e4cfca21..ff19e1c1 100644 --- a/Classes/Updates/BackendModuleUserPermission.php +++ b/Classes/Updates/BackendModuleUserPermission.php @@ -25,19 +25,16 @@ 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 @@ public function updateNecessary(): bool $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 @@ public function executeUpdate(): bool $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 @@ private function updateMods(string $mods): string { $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 @@ public function getPrerequisites(): array 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 00000000..05be5d24 --- /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 33481e4d..827a7813 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 00000000..cbc9b7a9 --- /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 7087a5ec..c1819f5f 100644 --- a/Configuration/Services.php +++ b/Configuration/Services.php @@ -6,17 +6,20 @@ 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 1eb4e24f..87b10268 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 @@ ], ]); - \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 576604ed..fecca3aa 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 @@ ], ]); - \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 379ee9f4..9f6c0c77 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 @@ ], ]); - \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 1ef5ccdb..b86db909 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 @@ 'config' => [ 'type' => 'input', 'max' => 255, - 'eval' => 'required,trim,unique', + 'eval' => 'trim,unique', + 'required' => true, ], ], 'type' => [ @@ -38,16 +42,16 @@ '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 @@ ], 'tstamp' => [ 'config' => [ - 'type' => 'input', - 'renderType' => 'inputDateTime', - 'eval' => 'datetime', + 'type' => 'datetime', + 'format' => 'datetime', 'readOnly' => true, ], ], @@ -89,4 +92,4 @@ ], ], ]; -})(\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 c679555d..6104523a 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 @@ 'crdate' => [ 'label' => $languagePath . '.crdate', 'config' => [ - 'type' => 'input', - 'renderType' => 'inputDateTime', - 'eval' => 'datetime', + 'type' => 'datetime', + 'format' => 'datetime', 'readOnly' => true, ], ], @@ -57,4 +59,4 @@ ], ], ]; -})(\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 3edf288a..5ce7baa8 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 @@ '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 @@ 'renderType' => 'checkboxLabeledToggle', 'items' => [ [ - 0 => '', - 1 => '', 'labelChecked' => $languagePath . '.insertion.yes', 'labelUnchecked' => $languagePath . '.insertion.no', ], @@ -98,9 +99,8 @@ 'crdate' => [ 'label' => $languagePath . '.crdate', 'config' => [ - 'type' => 'input', - 'renderType' => 'inputDateTime', - 'eval' => 'datetime', + 'type' => 'datetime', + 'format' => 'datetime', 'readOnly' => true, ], ], @@ -120,4 +120,4 @@ ], ], ]; -})(\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 0d37b72b..a5840af4 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 @@ 'tstamp' => [ 'label' => $languagePath . '.tstamp', 'config' => [ - 'type' => 'input', - 'renderType' => 'inputDateTime', - 'eval' => 'datetime', + 'type' => 'datetime', + 'format' => 'datetime', 'readOnly' => true, ], ], @@ -88,4 +90,4 @@ ], ], ]; -})(\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 1d1e5bfe..ec1cdb69 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 @@ '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 @@ '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 @@ 'renderType' => 'checkboxToggle', 'items' => [ [ - 0 => '', - 1 => '', - 'invertStateDisplay' => true - ] + 'invertStateDisplay' => true, + ], ], - ] + ], ], 'title' => [ @@ -190,8 +186,8 @@ 'default' => '0', 'items' => [ [ - $languagePath . '.town.unkown', - 0, + 'label' => $languagePath . '.town.unkown', + 'value' => 0, ], ], 'readOnly' => true, @@ -207,8 +203,8 @@ 'default' => '0', 'items' => [ [ - $languagePath . '.managed_by.unkown', - 0, + 'label' => $languagePath . '.managed_by.unkown', + 'value' => 0, ], ], 'readOnly' => true, @@ -227,4 +223,4 @@ ], ], ]; -})(\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 5c6a48fe..8a93e9f5 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 @@ '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 @@ '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 @@ 'default' => '0', 'items' => [ [ - $languagePath . '.town.unkown', - 0, + 'label' => $languagePath . '.town.unkown', + 'value' => 0, ], ], 'readOnly' => true, @@ -286,8 +284,8 @@ 'default' => '0', 'items' => [ [ - $languagePath . '.managed_by.unkown', - 0, + 'label' => $languagePath . '.managed_by.unkown', + 'value' => 0, ], ], 'readOnly' => true, @@ -298,12 +296,11 @@ '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 @@ '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 @@ ], ], ]; -})(\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 4b0afbf4..e8e041f1 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 @@ 'default' => '0', 'items' => [ [ - $languagePath . '.town.unkown', - 0, + 'label' => $languagePath . '.town.unkown', + 'value' => 0, ], ], 'readOnly' => true, @@ -68,8 +71,8 @@ 'default' => '0', 'items' => [ [ - $languagePath . '.managed_by.unkown', - 0, + 'label' => $languagePath . '.managed_by.unkown', + 'value' => 0, ], ], 'readOnly' => true, @@ -82,4 +85,4 @@ ], ], ]; -})(\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 7cfe603c..9eb4d8e9 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 @@ 'foreign_table' => 'tx_thuecat_organisation', 'items' => [ [ - $languagePath . '.managed_by.unkown', - 0, + 'label' => $languagePath . '.managed_by.unkown', + 'value' => 0, ], ], 'readOnly' => true, @@ -74,4 +77,4 @@ ], ], ]; -})(\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 00000000..239b5337 --- /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 4a5ef2a2..59bc1fa2 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 bc795261..14ca3832 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 00000000..338adc03 --- /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 2aba0dff..00000000 --- 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 e88e28ef..160692e5 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 29dfb60c..14e12146 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 cee06104..b75f2feb 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.parkingFacilitiesNearBy', extensionName: 'Thuecat'
-

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

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

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

{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 d99b3ad6..00000000 --- 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 00000000..88e9cae8 --- /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 8ac78d28..5ebb41e9 100644 --- a/Tests/Acceptance/Support/AcceptanceTester.php +++ b/Tests/Acceptance/Support/AcceptanceTester.php @@ -29,6 +29,7 @@ /** * 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 59433baa..64877100 100644 --- a/Tests/Acceptance/Support/Environment.php +++ b/Tests/Acceptance/Support/Environment.php @@ -23,6 +23,8 @@ 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 @@ */ 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 c96a04f0..00000000 --- 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 31d8075e..a5c0b4a9 100644 --- a/Tests/Functional/AbstractImportTest.php +++ b/Tests/Functional/AbstractImportTestCase.php @@ -23,17 +23,18 @@ 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 @@ protected function setUp(): void '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 @@ protected function setUp(): void ]); parent::setUp(); - GuzzleClientFaker::registerClient(); - - $this->setUpBackendUserFromFixture(1); - - $GLOBALS['LANG'] = $this->getContainer()->get(LanguageService::class); + GuzzleClientFaker::registerClient(); + $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 @@ protected function assertPostConditions(): void 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 @@ protected function tearDown(): void $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 00000000..b72404b4 --- /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 00000000..fa570d3b --- /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 00000000..a1229001 --- /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 00000000..d4a2fc1a --- /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 00000000..f8aa424b --- /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 00000000..68c14ee6 --- /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 00000000..6ba52a88 --- /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 00000000..14a4a9a2 --- /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 00000000..62d8aa2a --- /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 00000000..aa987af0 --- /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 00000000..3be421fb --- /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 00000000..ed38a726 --- /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 00000000..1e422c15 --- /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 00000000..1e422c15 --- /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 00000000..719137f9 --- /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 e04ae056..00000000 --- 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 00000000..9b4dedb9 --- /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 8ec52b8c..00000000 --- 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 00000000..4e3bb120 --- /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 d7de1d01..00000000 --- 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 00000000..6800373a --- /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 26422a2f..00000000 --- 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 00000000..00194772 --- /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 964911cb..00000000 --- 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 00000000..586d4252 --- /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 6708c579..00000000 --- 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 00000000..31a6a059 --- /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 ad4a3062..00000000 --- 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 00000000..0def6bad --- /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 bb86587f..00000000 --- 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 00000000..d9495cc5 --- /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 5604dd98..00000000 --- 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 00000000..dcab1b9a --- /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 d2c38575..00000000 --- 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 00000000..0f878d02 --- /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 868d9817..00000000 --- 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 3d5e735b..4a18bb2c 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 4d34c991..00000000 --- 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 00000000..76b4405f --- /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 e756748e..00000000 --- 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 b8d795ca..00000000 --- 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 c78bae89..4c382b5b 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 3de37034..00000000 --- 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 00000000..d4a2fc1a --- /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 72ebe263..00000000 --- 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 8ab2f778..c89b3913 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 9df311f4..00000000 --- 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 00000000..548bb801 --- /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 dfc6f48a..00000000 --- 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 4e41dfc3..00000000 --- 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 00000000..665cde5c --- /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 0754c1b5..00000000 --- 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 00000000..8c251b33 --- /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 8f0ca7ee..00000000 --- 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 7d1f60c6..00000000 --- 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 00000000..56dc92e0 --- /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 d48484fd..00000000 --- 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 00000000..74e887f0 --- /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 50c2234e..00000000 --- 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 10e195df..00000000 --- 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 00000000..62d8aa2a --- /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 6d8057fe..00000000 --- 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 7a7fecb8..2a149f86 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 8e2b1767..00000000 --- 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 00000000..3be421fb --- /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 8e13dd4b..00000000 --- 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 00000000..5c30d9b5 --- /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 853f0800..00000000 --- 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 ad43804e..00000000 --- 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 00000000..0c36017f --- /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 42a04459..00000000 --- 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 ad43804e..00000000 --- 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 00000000..9c277ca7 --- /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 1920bf9f..00000000 --- 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 00000000..4cc81ebc --- /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 fb467472..00000000 --- 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 4d204f43..7848a6a4 100644 --- a/Tests/Functional/FrontendTest.php +++ b/Tests/Functional/FrontendTest.php @@ -23,11 +23,16 @@ 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 @@ protected function setUp(): void ]; $this->testExtensionsToLoad = [ - 'typo3conf/ext/thuecat/', + 'werkraummedia/thuecat', ]; $this->pathsToLinkInTestInstance = [ @@ -44,7 +49,7 @@ protected function setUp(): void 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 @@ protected function setUp(): void ]); } - /** - * @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 @@ public function touristAttractionContentElementIsRendered(): void 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 @@ public function touristAttractionContentElementRespectsEditorialSorting(): void $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 @@ public function touristAttractionContentElementRespectsEditorialSorting(): void ); } - /** - * @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 @@ public function pricesAreSorted(): void ); } - /** - * @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 @@ public function offersAreSortedByType(): void ); } - /** - * @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 @@ public function openingHoursAreFilteredByThough(): void ], ])], ['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 @@ public function openingHoursAreFilteredByThough(): void 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 @@ public function openingHoursAreSortedByFrom(): void ], ])], ['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 @@ public function openingHoursAreSortedByFrom(): void 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 @@ public function specialOpeningHoursAreRendered(): void ], ])], ['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 @@ public function specialOpeningHoursAreRendered(): void 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 27295b6a..1a0d01b2 100644 --- a/Tests/Functional/GuzzleClientFaker.php +++ b/Tests/Functional/GuzzleClientFaker.php @@ -4,16 +4,14 @@ 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 @@ public static function registerClient(): void $GLOBALS['TYPO3_CONF_VARS']['HTTP']['handler']['faker'] = function (callable $handler) { return self::getMockHandler(); }; - } /** @@ -40,7 +37,7 @@ public static function appendResponseFromFile(string $fileName): void { $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 e9d46d86..c46ef5f5 100644 --- a/Tests/Functional/Import/EntityMapping/BaseInfosTest.php +++ b/Tests/Functional/Import/EntityMapping/BaseInfosTest.php @@ -23,23 +23,16 @@ 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 @@ public function instanceOfBaseIsReturnedIfRequestes(): void self::assertInstanceOf(Base::class, $result); } - /** - * @test - */ + #[Test] public function returnsDefaultValuesIfNotProvidedForMapping(): void { $subject = new EntityMapper(); @@ -74,9 +65,7 @@ public function returnsDefaultValuesIfNotProvidedForMapping(): void self::assertNull($result->getManagedBy()); } - /** - * @test - */ + #[Test] public function mapsIncomingDataToProperties(): void { $subject = new EntityMapper(); @@ -97,9 +86,7 @@ public function mapsIncomingDataToProperties(): void self::assertSame(['https://example.com/the-thing'], $result->getUrls()); } - /** - * @test - */ + #[Test] public function mapsIncomingPhoto(): void { $subject = new EntityMapper(); @@ -117,9 +104,7 @@ public function mapsIncomingPhoto(): void self::assertSame('https://thuecat.org/resources/835224016581-dara', $result->getPhoto()->getId()); } - /** - * @test - */ + #[Test] public function mapsIncomingImages(): void { $subject = new EntityMapper(); @@ -146,9 +131,7 @@ public function mapsIncomingImages(): void 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 3fead387..1feb7440 100644 --- a/Tests/Functional/Import/EntityMapping/JsonDecodingTest.php +++ b/Tests/Functional/Import/EntityMapping/JsonDecodingTest.php @@ -23,17 +23,13 @@ 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 @@ public function canBeCreated(): void ); } - /** - * @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 @@ public function decodesPropertyWithMultipleLanguagesProvidingActiveOne(): void ], $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 @@ public function decodesPropertyWithSingleLanguageMatchingActive(): void ], $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 @@ public function decodesPropertyWithSingleLanguageNotMatchingActive(): void ], $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 @@ public function decodesPropertyWithMultipleLanguagesAndFormatsProvidingActiveLan ], $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 @@ public function decodesPropertyWithMultipleLanguagesNotMatchingRequestOne(): voi ], $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 @@ public function decodesSingleValueNotRelatedToLanguage(): void ], $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 @@ public function decodesNestedObjectStructures(): void ], $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 @@ public function decodesOpeningHours(): void ], $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 654d4ff6..1b6f77b5 100644 --- a/Tests/Functional/Import/EntityMapping/PlaceInfosTest.php +++ b/Tests/Functional/Import/EntityMapping/PlaceInfosTest.php @@ -21,25 +21,18 @@ * 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 @@ public function instanceOfPlaceIsReturnedIfRequestes(): void self::assertInstanceOf(Place::class, $result); } - /** - * @test - */ + #[Test] public function returnsDefaultValuesIfNotProvidedForMapping(): void { $subject = new EntityMapper(); @@ -68,9 +59,7 @@ public function returnsDefaultValuesIfNotProvidedForMapping(): void self::assertSame([], $result->getOpeningHoursSpecification()); } - /** - * @test - */ + #[Test] public function mapsIncomingAddress(): void { $subject = new EntityMapper(); @@ -136,9 +125,7 @@ public function mapsIncomingAddress(): void self::assertSame('dominformation@domberg-erfurt.de', $result->getAddress()->getEmail()); } - /** - * @test - */ + #[Test] public function mapsIncomingMultipleUrls(): void { $subject = new EntityMapper(); @@ -165,9 +152,7 @@ public function mapsIncomingMultipleUrls(): void ], $result->getUrls()); } - /** - * @test - */ + #[Test] public function mapsIncomingSingleUrl(): void { $subject = new EntityMapper(); diff --git a/Tests/Functional/ImportConfigurationCommandTest.php b/Tests/Functional/ImportConfigurationCommandTest.php index eb5e1e5d..5289f2b4 100644 --- a/Tests/Functional/ImportConfigurationCommandTest.php +++ b/Tests/Functional/ImportConfigurationCommandTest.php @@ -24,37 +24,30 @@ 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 @@ public function throwsExceptionOnNoneExistingConfiguration(): void $tester->execute(['configuration' => 1], ['capture_stderr_separately' => true]); } - /** - * @test - */ + #[Test] public function throwsExceptionOnMissingArgument(): void { $subject = $this->getContainer()->get(ImportConfigurationCommand::class); @@ -86,9 +77,7 @@ public function throwsExceptionOnMissingArgument(): void $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 2a570f26..a30e2fec 100644 --- a/Tests/Functional/ImportTest.php +++ b/Tests/Functional/ImportTest.php @@ -23,66 +23,31 @@ * 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 @@ public function updatesExistingOrganization(): void 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 @@ public function importsTouristAttractionsWithRelations(): void 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 @@ public function importsBasedOnSyncScope(): void 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 @@ public function importsBasedOnContainsPlace(): void 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 @@ public function importsFollowingRecordsInCaseOfAnMappingException(): void 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 @@ public function importWithMultipleReferencesToSameObject(): void 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 @@ public function importsTouristAttractionWithMedia(): void 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 00000000..01bc871c --- /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 403e40cf..93bcd364 100644 --- a/Tests/Unit/Domain/Import/ImportTest.php +++ b/Tests/Unit/Domain/Import/ImportTest.php @@ -23,20 +23,16 @@ 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 @@ public function canBeCreated(): void ); } - /** - * @test - */ + #[Test] public function canStart(): void { $configuration = new ImportConfiguration(); @@ -66,9 +60,7 @@ public function canStart(): void ); } - /** - * @test - */ + #[Test] public function canEndAfterStart(): void { $configuration = new ImportConfiguration(); @@ -86,9 +78,7 @@ public function canEndAfterStart(): void ); } - /** - * @test - */ + #[Test] public function isDoneAfterStartAndEnd(): void { $configuration = new ImportConfiguration(); @@ -99,9 +89,7 @@ public function isDoneAfterStartAndEnd(): void self::assertTrue($subject->done()); } - /** - * @test - */ + #[Test] public function isNotDoneAfterJustStartWithoutEnd(): void { $configuration = new ImportConfiguration(); @@ -111,9 +99,7 @@ public function isNotDoneAfterJustStartWithoutEnd(): void self::assertFalse($subject->done()); } - /** - * @test - */ + #[Test] public function nestedStartReturnsExpectedConfiguration(): void { $configuration1 = new ImportConfiguration(); @@ -129,9 +115,7 @@ public function nestedStartReturnsExpectedConfiguration(): void ); } - /** - * @test - */ + #[Test] public function nestedStartReturnsExpectedLog(): void { $configuration1 = new ImportConfiguration(); @@ -159,9 +143,7 @@ public function nestedStartReturnsExpectedLog(): void ); } - /** - * @test - */ + #[Test] public function nestedImportMergesLog(): void { $configuration1 = new ImportConfiguration(); @@ -183,15 +165,13 @@ public function nestedImportMergesLog(): void 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 107c695b..d604e759 100644 --- a/Tests/Unit/Domain/Import/Importer/FetchDataTest.php +++ b/Tests/Unit/Domain/Import/Importer/FetchDataTest.php @@ -23,23 +23,21 @@ * 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 @@ public function canBeCreated(): void self::assertInstanceOf(FetchData::class, $subject); } - /** - * @test - */ + #[Test] public function returnsParsedJsonLdBasedOnUrl(): void { $requestFactory = $this->createStub(RequestFactoryInterface::class); @@ -70,8 +66,11 @@ public function returnsParsedJsonLdBasedOnUrl(): void $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 @@ public function returnsParsedJsonLdBasedOnUrl(): void ], $result); } - /** - * @test - */ + #[Test] public function returnsEmptyArrayInCaseOfError(): void { $requestFactory = $this->createStub(RequestFactoryInterface::class); @@ -105,8 +102,11 @@ public function returnsEmptyArrayInCaseOfError(): void $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 @@ public function returnsEmptyArrayInCaseOfError(): void self::assertSame([], $result); } - /** - * @test - */ + #[Test] public function returnsResultFromCacheIfAvailable(): void { $requestFactory = $this->createStub(RequestFactoryInterface::class); @@ -151,9 +149,7 @@ public function returnsResultFromCacheIfAvailable(): void ], $result); } - /** - * @test - */ + #[Test] public function throwsExceptionOn404(): void { $requestFactory = $this->createStub(RequestFactoryInterface::class); @@ -163,14 +159,19 @@ public function throwsExceptionOn404(): void $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 @@ public function throwsExceptionOn404(): void $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 1864a998..674010df 100644 --- a/Tests/Unit/Domain/Import/Model/EntityCollectionTest.php +++ b/Tests/Unit/Domain/Import/Model/EntityCollectionTest.php @@ -23,18 +23,14 @@ * 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 @@ public function canBeCreated(): void self::assertInstanceOf(EntityCollection::class, $subject); } - /** - * @test - */ + #[Test] public function returnsEmptyArrayAsDefaultEntities(): void { $subject = new EntityCollection(); @@ -52,9 +46,7 @@ public function returnsEmptyArrayAsDefaultEntities(): void self::assertSame([], $subject->getEntities()); } - /** - * @test - */ + #[Test] public function returnsFirstEntityForDefaultLanguage(): void { $entityWithTranslation = $this->createStub(Entity::class); @@ -73,9 +65,7 @@ public function returnsFirstEntityForDefaultLanguage(): void ); } - /** - * @test - */ + #[Test] public function returnsNullIfNoEntityForDefaultLanguageExists(): void { $entityWithTranslation = $this->createStub(Entity::class); @@ -89,9 +79,7 @@ public function returnsNullIfNoEntityForDefaultLanguageExists(): void ); } - /** - * @test - */ + #[Test] public function returnsEntitiesToTranslate(): void { $entityWithTranslation = $this->createStub(Entity::class); @@ -109,9 +97,7 @@ public function returnsEntitiesToTranslate(): void ); } - /** - * @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 e02cf208..6d5a1292 100644 --- a/Tests/Unit/Domain/Import/Model/GenericEntityTest.php +++ b/Tests/Unit/Domain/Import/Model/GenericEntityTest.php @@ -23,17 +23,13 @@ * 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 @@ public function canBeCreated(): void self::assertInstanceOf(GenericEntity::class, $subject); } - /** - * @test - */ + #[Test] public function returnsTypo3StoragePid(): void { $subject = new GenericEntity( @@ -61,9 +55,7 @@ public function returnsTypo3StoragePid(): void self::assertSame(10, $subject->getTypo3StoragePid()); } - /** - * @test - */ + #[Test] public function returnsTypo3DatabaseTableName(): void { $subject = new GenericEntity( @@ -76,9 +68,7 @@ public function returnsTypo3DatabaseTableName(): void self::assertSame('tx_thuecat_entity', $subject->getTypo3DatabaseTableName()); } - /** - * @test - */ + #[Test] public function returnsTypo3SystemLanguageUid(): void { $subject = new GenericEntity( @@ -91,9 +81,7 @@ public function returnsTypo3SystemLanguageUid(): void self::assertSame(10, $subject->getTypo3SystemLanguageUid()); } - /** - * @test - */ + #[Test] public function claimsIsForDefaultLanguage(): void { $subject = new GenericEntity( @@ -106,9 +94,7 @@ public function claimsIsForDefaultLanguage(): void self::assertTrue($subject->isForDefaultLanguage()); } - /** - * @test - */ + #[Test] public function claimsIsTranslation(): void { $subject = new GenericEntity( @@ -121,9 +107,7 @@ public function claimsIsTranslation(): void self::assertTrue($subject->isTranslation()); } - /** - * @test - */ + #[Test] public function returnsRemoteId(): void { $subject = new GenericEntity( @@ -139,9 +123,7 @@ public function returnsRemoteId(): void ); } - /** - * @test - */ + #[Test] public function returnsData(): void { $subject = new GenericEntity( @@ -163,9 +145,7 @@ public function returnsData(): void ); } - /** - * @test - */ + #[Test] public function returnsNotCreatedByDefault(): void { $subject = new GenericEntity( @@ -180,9 +160,7 @@ public function returnsNotCreatedByDefault(): void ); } - /** - * @test - */ + #[Test] public function returnsNotExistingByDefault(): void { $subject = new GenericEntity( @@ -197,9 +175,7 @@ public function returnsNotExistingByDefault(): void ); } - /** - * @test - */ + #[Test] public function returnsZeroAsDefaultTypo3Uid(): void { $subject = new GenericEntity( @@ -215,9 +191,7 @@ public function returnsZeroAsDefaultTypo3Uid(): void ); } - /** - * @test - */ + #[Test] public function canBeMarkedAsImported(): void { $subject = new GenericEntity( @@ -234,9 +208,7 @@ public function canBeMarkedAsImported(): void 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 73dae8ed..54306d43 100644 --- a/Tests/Unit/Domain/Import/RequestFactoryTest.php +++ b/Tests/Unit/Domain/Import/RequestFactoryTest.php @@ -23,25 +23,22 @@ * 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 @@ public function canBeCreated(): void 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 @@ public function returnsRequestWithJsonIdFormat(): void 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 @@ public function returnsRequestWithApiKeyWhenConfigured(): void 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 699aec01..34eba577 100644 --- a/Tests/Unit/Domain/Import/Typo3Converter/GeneralConverterTest.php +++ b/Tests/Unit/Domain/Import/Typo3Converter/GeneralConverterTest.php @@ -23,14 +23,15 @@ 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\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 @@ public function canBeCreated(): void $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 @@ public function canBeCreated(): void ); } - /** - * @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 50d3e184..c1d175d6 100644 --- a/Tests/Unit/Domain/Import/Typo3Converter/NameExtractorTest.php +++ b/Tests/Unit/Domain/Import/Typo3Converter/NameExtractorTest.php @@ -23,6 +23,7 @@ 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\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 @@ public function canBeCreated(): void ); } - /** - * @test - */ + #[Test] public function extractsNameFromString(): void { $resolveForeignReference = $this->createStub(ResolveForeignReference::class); @@ -70,9 +64,7 @@ public function extractsNameFromString(): void ); } - /** - * @test - */ + #[Test] public function extractsNameFromForeignReference(): void { $place = $this->createStub(Place::class); @@ -91,9 +83,7 @@ public function extractsNameFromForeignReference(): void ); } - /** - * @test - */ + #[Test] public function extractsCombinedNameFromForeignReference(): void { $person = $this->createStub(Person::class); @@ -113,9 +103,7 @@ public function extractsCombinedNameFromForeignReference(): void ); } - /** - * @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 af77d8bd..a0f1f626 100644 --- a/Tests/Unit/Domain/Import/UrlProvider/RegistryTest.php +++ b/Tests/Unit/Domain/Import/UrlProvider/RegistryTest.php @@ -23,19 +23,15 @@ * 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 @@ public function canBeCreated(): void self::assertInstanceOf(Registry::class, $subject); } - /** - * @test - */ + #[Test] public function allowsRegistrationOfUrlProvider(): void { $subject = new Registry(); @@ -55,9 +49,7 @@ public function allowsRegistrationOfUrlProvider(): void self::assertTrue(true); } - /** - * @test - */ + #[Test] public function returnsNullIfNoProviderExistsForConfiguration(): void { $configuration = new ImportConfiguration(); @@ -68,9 +60,7 @@ public function returnsNullIfNoProviderExistsForConfiguration(): void 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 58e11227..ea04d46a 100644 --- a/Tests/Unit/Domain/Import/UrlProvider/StaticUrlProviderTest.php +++ b/Tests/Unit/Domain/Import/UrlProvider/StaticUrlProviderTest.php @@ -23,27 +23,21 @@ * 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 @@ public function canProvideForStaticConfiguration(): void self::assertTrue($result); } - /** - * @test - */ + #[Test] public function returnsConcreteProviderForConfiguration(): void { $configuration = new ImportConfiguration(); @@ -69,9 +61,7 @@ public function returnsConcreteProviderForConfiguration(): void 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 563345f6..085cd033 100644 --- a/Tests/Unit/Domain/Import/UrlProvider/SyncScopeUrlProviderTest.php +++ b/Tests/Unit/Domain/Import/UrlProvider/SyncScopeUrlProviderTest.php @@ -23,19 +23,15 @@ * 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 @@ public function canBeCreated(): void self::assertInstanceOf(SyncScopeUrlProvider::class, $subject); } - /** - * @test - */ + #[Test] public function canProvideForSyncScope(): void { $configuration = new ImportConfiguration(); @@ -65,9 +59,7 @@ public function canProvideForSyncScope(): void self::assertTrue($result); } - /** - * @test - */ + #[Test] public function returnsConcreteProviderForConfiguration(): void { $configuration = new ImportConfiguration(); @@ -92,9 +84,7 @@ public function returnsConcreteProviderForConfiguration(): void 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 9c7bfc41..3fba4ec9 100644 --- a/Tests/Unit/Domain/Model/Backend/ImportConfigurationTest.php +++ b/Tests/Unit/Domain/Model/Backend/ImportConfigurationTest.php @@ -23,17 +23,14 @@ * 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 @@ public function canBeCreated(): void self::assertInstanceOf(ImportConfiguration::class, $subject); } - /** - * @test - */ + #[Test] public function returnsTitle(): void { $subject = new ImportConfiguration(); @@ -52,9 +47,7 @@ public function returnsTitle(): void self::assertSame('Example Title', $subject->getTitle()); } - /** - * @test - */ + #[Test] public function returnsType(): void { $subject = new ImportConfiguration(); @@ -63,9 +56,7 @@ public function returnsType(): void self::assertSame('static', $subject->getType()); } - /** - * @test - */ + #[Test] public function returnsTableName(): void { $subject = new ImportConfiguration(); @@ -73,12 +64,10 @@ public function returnsTableName(): void 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 @@ public function returnsLastChanged(): void self::assertSame($lastChanged, $subject->getLastChanged()); } - /** - * @test - */ + #[Test] public function returnsStoragePidWhenSet(): void { $flexForm = implode(PHP_EOL, [ '', '', - '', - '', - '', - '', - '20', - '', - '', - '', - '', + '', + '', + '', + '', + '20', + '', + '', + '', + '', '', ]); @@ -114,9 +101,7 @@ public function returnsStoragePidWhenSet(): void self::assertSame(20, $subject->getStoragePid()); } - /** - * @test - */ + #[Test] public function returnsZeroAsStoragePidWhenNoConfigurationExists(): void { $flexForm = ''; @@ -128,23 +113,21 @@ public function returnsZeroAsStoragePidWhenNoConfigurationExists(): void self::assertSame(0, $subject->getStoragePid()); } - /** - * @test - */ + #[Test] public function returnsZeroAsStoragePidWhenNegativePidIsConfigured(): void { $flexForm = implode(PHP_EOL, [ '', '', - '', - '', - '', - '', - '-1', - '', - '', - '', - '', + '', + '', + '', + '', + '-1', + '', + '', + '', + '', '', ]); @@ -155,23 +138,21 @@ public function returnsZeroAsStoragePidWhenNegativePidIsConfigured(): void self::assertSame(0, $subject->getStoragePid()); } - /** - * @test - */ + #[Test] public function returnsZeroAsStoragePidWhenNoneNumericPidIsConfigured(): void { $flexForm = implode(PHP_EOL, [ '', '', - '', - '', - '', - '', - 'abc', - '', - '', - '', - '', + '', + '', + '', + '', + 'abc', + '', + '', + '', + '', '', ]); @@ -182,34 +163,32 @@ public function returnsZeroAsStoragePidWhenNoneNumericPidIsConfigured(): void 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 @@ public function returnsUrlsWhenSet(): void ], $subject->getUrls()); } - /** - * @test - */ + #[Test] public function returnsEmptyArrayAsUrlsWhenNoConfigurationExists(): void { $flexForm = ''; @@ -236,23 +213,21 @@ public function returnsEmptyArrayAsUrlsWhenNoConfigurationExists(): void self::assertSame([], $subject->getUrls()); } - /** - * @test - */ + #[Test] public function returnsEmptyArrayAsUrlsWhenNoUrlsAreConfigured(): void { $flexForm = implode(PHP_EOL, [ '', '', - '', - '', - '', - '', - '10', - '', - '', - '', - '', + '', + '', + '', + '', + '10', + '', + '', + '', + '', '', ]); @@ -263,23 +238,21 @@ public function returnsEmptyArrayAsUrlsWhenNoUrlsAreConfigured(): void 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 @@ public function returnsSyncScopeIdWhenSet(): void self::assertSame('dd4639dc-58a7-4648-a6ce-4950293a06db', $subject->getSyncScopeId()); } - /** - * @test - */ + #[Test] public function returnsEmptyStringAsSyncScopeIdWhenNoConfigurationExists(): void { $flexForm = ''; @@ -304,23 +275,21 @@ public function returnsEmptyStringAsSyncScopeIdWhenNoConfigurationExists(): void 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 2d19474c..3369e391 100644 --- a/Tests/Unit/Domain/Model/Backend/ImportLogTest.php +++ b/Tests/Unit/Domain/Model/Backend/ImportLogTest.php @@ -23,18 +23,14 @@ * 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 @@ public function canBeCreated(): void self::assertInstanceOf(ImportLog::class, $subject); } - /** - * @test - */ + #[Test] public function returnsConfigurationIfSet(): void { $configuration = new ImportConfiguration(); @@ -53,9 +47,7 @@ public function returnsConfigurationIfSet(): void self::assertSame($configuration, $subject->getConfiguration()); } - /** - * @test - */ + #[Test] public function returnsNullForConfigurationIfNotSet(): void { $subject = new ImportLog(); @@ -63,9 +55,7 @@ public function returnsNullForConfigurationIfNotSet(): void self::assertNull($subject->getConfiguration()); } - /** - * @test - */ + #[Test] public function returnsConfigurationUidIfSet(): void { $configuration = new ImportConfiguration(); @@ -75,9 +65,7 @@ public function returnsConfigurationUidIfSet(): void 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 05300665..5042e545 100644 --- a/Tests/Unit/Domain/Model/Frontend/AddressTest.php +++ b/Tests/Unit/Domain/Model/Frontend/AddressTest.php @@ -23,17 +23,13 @@ * 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 @@ public function canBeCreated(): void self::assertInstanceOf(Address::class, $subject); } - /** - * @test - */ + #[Test] public function returnsProperDefaults(): void { $subject = new Address('[]'); @@ -56,9 +50,7 @@ public function returnsProperDefaults(): void self::assertSame('', $subject->getFax()); } - /** - * @test - */ + #[Test] public function returnsStreet(): void { $subject = new Address('{"street": "Example Street 10"}'); @@ -66,9 +58,7 @@ public function returnsStreet(): void self::assertSame('Example Street 10', $subject->getStreet()); } - /** - * @test - */ + #[Test] public function returnsZip(): void { $subject = new Address('{"zip": "09084"}'); @@ -76,9 +66,7 @@ public function returnsZip(): void self::assertSame('09084', $subject->getZip()); } - /** - * @test - */ + #[Test] public function returnsCity(): void { $subject = new Address('{"city": "Erfurt"}'); @@ -86,9 +74,7 @@ public function returnsCity(): void self::assertSame('Erfurt', $subject->getCity()); } - /** - * @test - */ + #[Test] public function returnsEmail(): void { $subject = new Address('{"email": "example@example.com"}'); @@ -96,9 +82,7 @@ public function returnsEmail(): void self::assertSame('example@example.com', $subject->getEmail()); } - /** - * @test - */ + #[Test] public function returnsPhone(): void { $subject = new Address('{"phone": "+49 361 99999"}'); @@ -106,9 +90,7 @@ public function returnsPhone(): void self::assertSame('+49 361 99999', $subject->getPhone()); } - /** - * @test - */ + #[Test] public function returnsFax(): void { $subject = new Address('{"fax": "+49 361 99998"}'); @@ -116,9 +98,7 @@ public function returnsFax(): void self::assertSame('+49 361 99998', $subject->getFax()); } - /** - * @test - */ + #[Test] public function returnsLatitude(): void { $subject = new Address('{"geo": {"latitude": 50.978765}}'); @@ -126,9 +106,7 @@ public function returnsLatitude(): void self::assertSame(50.978765, $subject->getLatitute()); } - /** - * @test - */ + #[Test] public function returnsLongitude(): void { $subject = new Address('{"geo": {"longitude": 11.029133}}'); @@ -136,13 +114,11 @@ public function returnsLongitude(): void 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 f41f15d1..0b08d64d 100644 --- a/Tests/Unit/Domain/Model/Frontend/MediaTest.php +++ b/Tests/Unit/Domain/Model/Frontend/MediaTest.php @@ -23,18 +23,14 @@ * 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 @@ public function canBeCreated(): void 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 @@ public function returnsMainImageIfPresent(): void ], $subject->getMainImage()); } - /** - * @test - */ + #[Test] public function returnsEmptyArrayAsMainImageFallback(): void { $subject = new Media('[]'); @@ -66,9 +58,7 @@ public function returnsEmptyArrayAsMainImageFallback(): void 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 @@ public function returnsImagesAsArray(): void ], $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 @@ public function returnsExtraImagesAsArray(): void ], $subject->getExtraImages()); } - /** - * @test - */ + #[Test] public function doesNotAddCopyrightAuthorIfItDoesntExist(): void { $subject = new Media(json_encode([ @@ -131,9 +117,7 @@ public function doesNotAddCopyrightAuthorIfItDoesntExist(): void ); } - /** - * @test - */ + #[Test] public function addsCopyrightAuthorFromLicenseAuthor(): void { $subject = new Media(json_encode([ @@ -165,9 +149,7 @@ public function addsCopyrightAuthorFromLicenseAuthor(): void ); } - /** - * @test - */ + #[Test] public function addsCopyrightAuthorFromAuthor(): void { $subject = new Media(json_encode([ @@ -195,9 +177,7 @@ public function addsCopyrightAuthorFromAuthor(): void ); } - /** - * @test - */ + #[Test] public function addsCopyrightAuthorFromAuthorWithHigherPrio(): void { $subject = new Media(json_encode([ @@ -231,9 +211,7 @@ public function addsCopyrightAuthorFromAuthorWithHigherPrio(): void ); } - /** - * @test - */ + #[Test] public function returnsEmptyArrayAsDefaultForEditorialImages(): void { $subject = new Media(''); @@ -243,9 +221,7 @@ public function returnsEmptyArrayAsDefaultForEditorialImages(): void ); } - /** - * @test - */ + #[Test] public function returnsSetEditorialImages(): void { $subject = new Media(''); @@ -263,9 +239,7 @@ public function returnsSetEditorialImages(): void self::assertSame($reference2, $images[1]); } - /** - * @test - */ + #[Test] public function returnsEmptyArrayAsDefaultForAllImages(): void { $subject = new Media(''); @@ -275,9 +249,7 @@ public function returnsEmptyArrayAsDefaultForAllImages(): void ); } - /** - * @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 dda90214..bfbb9204 100644 --- a/Tests/Unit/Domain/Model/Frontend/OfferTest.php +++ b/Tests/Unit/Domain/Model/Frontend/OfferTest.php @@ -23,17 +23,13 @@ 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 @@ public function canBeCreatedWithLegacyTypeAsString(): void self::assertSame('LegacyType', $subject->getType()); } - /** - * @test - */ + #[Test] public function canBeCreatedWithSingleType(): void { $subject = Offer::createFromArray([ @@ -71,9 +65,7 @@ public function canBeCreatedWithSingleType(): void self::assertSame('ParkingFee', $subject->getType()); } - /** - * @test - */ + #[Test] public function canBeCreatedWithMultipleTypes(): void { $subject = Offer::createFromArray([ @@ -91,9 +83,7 @@ public function canBeCreatedWithMultipleTypes(): void 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 6e929a3f..d0a0c734 100644 --- a/Tests/Unit/Domain/Model/Frontend/OffersTest.php +++ b/Tests/Unit/Domain/Model/Frontend/OffersTest.php @@ -23,22 +23,16 @@ * 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 @@ public function canBeCreated(): void 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 @@ public function returnsExpectedCount(string $serialized, int $expected): void 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 2f896c0b..38b91cd3 100644 --- a/Tests/Unit/Domain/Model/Frontend/OpeningHourTest.php +++ b/Tests/Unit/Domain/Model/Frontend/OpeningHourTest.php @@ -23,17 +23,13 @@ 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 @@ public function returnsReducedOpens(): void ); } - /** - * @test - */ + #[Test] public function returnsOpensForEmptyString(): void { $subject = OpeningHour::createFromArray([]); @@ -59,9 +53,7 @@ public function returnsOpensForEmptyString(): void ); } - /** - * @test - */ + #[Test] public function returnsReducedCloses(): void { $subject = OpeningHour::createFromArray([ @@ -74,9 +66,7 @@ public function returnsReducedCloses(): void ); } - /** - * @test - */ + #[Test] public function returnsClosesForEmptyString(): void { $subject = OpeningHour::createFromArray([]); @@ -87,9 +77,7 @@ public function returnsClosesForEmptyString(): void ); } - /** - * @test - */ + #[Test] public function returnsThatThisIsOnlyASingleDay(): void { $subject = OpeningHour::createFromArray([ @@ -108,9 +96,7 @@ public function returnsThatThisIsOnlyASingleDay(): void 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 5159d560..61d99f7e 100644 --- a/Tests/Unit/Domain/Model/Frontend/TouristAttractionTest.php +++ b/Tests/Unit/Domain/Model/Frontend/TouristAttractionTest.php @@ -23,6 +23,9 @@ 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\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 @@ private function parkingFacilityWithTitle(string $title): ParkingFacility return $facility; } - /** - * @test - */ + #[Test] public function returnsDistanceToPublicTransportArrayWithoutTypes(): void { $subject = new TouristAttraction(); @@ -88,9 +83,7 @@ public function returnsDistanceToPublicTransportArrayWithoutTypes(): void ], $subject->getDistanceToPublicTransport()); } - /** - * @test - */ + #[Test] public function returnsDistanceToPublicTransportArrayWithTwoTypes(): void { $subject = new TouristAttraction(); @@ -106,12 +99,10 @@ public function returnsDistanceToPublicTransportArrayWithTwoTypes(): void ], $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 @@ public function filterOutPreviousDates( '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 @@ public function filterOutPreviousDates( '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 @@ public function filterOutPreviousDates( '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 @@ public function filterOutPreviousDates( 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 @@ public function filterOutPreviousDates( } } - /** - * @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 @@ public function filterOutPreviousDates( '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 @@ public function filterOutPreviousDates( '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 @@ public function filterOutPreviousDates( '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 @@ public function filterOutPreviousDates( 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 492bc49e..ff8d40b1 100644 --- a/Tests/Unit/ExtensionTest.php +++ b/Tests/Unit/ExtensionTest.php @@ -23,18 +23,13 @@ * 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 ba129f46..336dd7d9 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 2307d86d..00000000 --- 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 ec918cb3..1d922582 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 5fd44236..537e04fd 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 f338cb80..00000000 --- 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 @@ -245,96 +216,26 @@ parameters: 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\\.$#" + message: "#^Cannot call method getLanguageOverlay\\(\\) on string\\|TYPO3\\\\CMS\\\\Core\\\\Domain\\\\Repository\\\\PageRepository\\.$#" 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\\.$#" + message: "#^Parameter \\#1 \\$className of method TYPO3\\\\CMS\\\\Extbase\\\\Persistence\\\\Generic\\\\Mapper\\\\DataMapper\\:\\:map\\(\\) expects class\\-string\\, string given\\.$#" count: 1 path: Classes/Frontend/DataProcessing/ResolveEntities.php - - message: "#^Cannot call method getLanguageOverlay\\(\\) on string\\|TYPO3\\\\CMS\\\\Core\\\\Domain\\\\Repository\\\\PageRepository\\.$#" + message: "#^Unable to resolve the template type T in call to method TYPO3\\\\CMS\\\\Extbase\\\\Persistence\\\\Generic\\\\Mapper\\\\DataMapper\\:\\:map\\(\\)$#" count: 1 path: Classes/Frontend/DataProcessing/ResolveEntities.php - - message: "#^Right side of \\|\\| is always false\\.$#" - count: 1 - path: Configuration/TCA/Overrides/pages.php - - - - message: "#^Right side of \\|\\| is always false\\.$#" - count: 1 - path: Configuration/TCA/Overrides/pages_tourist_attraction.php - - - - message: "#^Right side of \\|\\| is always false\\.$#" - count: 1 - path: Configuration/TCA/Overrides/sys_template.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/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 + path: Classes/Updates/BackendModuleUserPermission.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\\.$#" + message: "#^Method WerkraumMedia\\\\ThueCat\\\\Tests\\\\Acceptance\\\\Support\\\\Environment\\:\\:bootstrapTypo3Environment\\(\\) has no return type specified\\.$#" count: 1 - path: Classes/Domain/Model/Frontend/Place.php + path: Tests/Acceptance/Support/Environment.php diff --git a/phpstan.neon b/phpstan.neon index 5df37284..bef4063f 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 4d4f27c0..95cb5b74 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 613b42c9..9ca6aee8 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 ];