Initial import mechanism

Provide first basic import mechanism.
It already allows to import entities into TYPO3 database.
Three entities are supported.

Entities are configured through import configuration.
This can be created, viewed, and edited through backend module.

Imports are tracked and accessible from backend module.

Still this is basic.
Importing lists of entities is not supported.
Multiple languages is not supported, etc.

Relates: #8214
pull/3/head
Daniel Siepmann 2 years ago
parent 7386a0601a
commit dc1c45f1c1
  1. 59
      Classes/Controller/Backend/AbstractController.php
  2. 80
      Classes/Controller/Backend/ImportController.php
  3. 58
      Classes/Controller/Backend/OverviewController.php
  4. 48
      Classes/DependencyInjection/ConverterPass.php
  5. 48
      Classes/DependencyInjection/UrlProvidersPass.php
  6. 37
      Classes/Domain/Import/Converter/Converter.php
  7. 47
      Classes/Domain/Import/Converter/Organisation.php
  8. 48
      Classes/Domain/Import/Converter/Registry.php
  9. 72
      Classes/Domain/Import/Converter/TouristInformation.php
  10. 58
      Classes/Domain/Import/Converter/Town.php
  11. 93
      Classes/Domain/Import/Importer.php
  12. 51
      Classes/Domain/Import/Importer/FetchData.php
  13. 102
      Classes/Domain/Import/Importer/SaveData.php
  14. 65
      Classes/Domain/Import/Model/Entity.php
  15. 88
      Classes/Domain/Import/Model/GenericEntity.php
  16. 41
      Classes/Domain/Import/RequestFactory.php
  17. 53
      Classes/Domain/Import/UrlProvider/Registry.php
  18. 57
      Classes/Domain/Import/UrlProvider/StaticUrlProvider.php
  19. 38
      Classes/Domain/Import/UrlProvider/UrlProvider.php
  20. 54
      Classes/Domain/Model/Backend/AbstractEntity.php
  21. 77
      Classes/Domain/Model/Backend/ImportConfiguration.php
  22. 114
      Classes/Domain/Model/Backend/ImportLog.php
  23. 97
      Classes/Domain/Model/Backend/ImportLogEntry.php
  24. 54
      Classes/Domain/Model/Backend/Organisation.php
  25. 28
      Classes/Domain/Model/Backend/TouristInformation.php
  26. 39
      Classes/Domain/Model/Backend/Town.php
  27. 42
      Classes/Domain/Repository/Backend/ImportConfigurationRepository.php
  28. 90
      Classes/Domain/Repository/Backend/ImportLogRepository.php
  29. 44
      Classes/Domain/Repository/Backend/OrganisationRepository.php
  30. 56
      Classes/Domain/Repository/Backend/TownRepository.php
  31. 59
      Classes/Extension.php
  32. 37
      Classes/Typo3Wrapper/TranslationService.php
  33. 65
      Classes/View/Backend/Menu.php
  34. 22
      Configuration/Extbase/Persistence/Classes.php
  35. 39
      Configuration/FlexForm/ImportConfiguration/Static.xml
  36. 18
      Configuration/Services.php
  37. 12
      Configuration/Services.yaml
  38. 4
      Configuration/SiteConfiguration/Overrides/sites.php
  39. 71
      Configuration/TCA/tx_thuecat_import_configuration.php
  40. 57
      Configuration/TCA/tx_thuecat_import_log.php
  41. 88
      Configuration/TCA/tx_thuecat_import_log_entry.php
  42. 81
      Configuration/TCA/tx_thuecat_organisation.php
  43. 82
      Configuration/TCA/tx_thuecat_tourist_information.php
  44. 76
      Configuration/TCA/tx_thuecat_town.php
  45. 102
      Resources/Private/Language/locallang.xlf
  46. 2
      Resources/Private/Language/locallang_be.xlf
  47. 17
      Resources/Private/Language/locallang_flexform.xlf
  48. 17
      Resources/Private/Language/locallang_mod.xlf
  49. 133
      Resources/Private/Language/locallang_tca.xlf
  50. 54
      Resources/Private/Templates/Backend/Import/Index.html
  51. 138
      Resources/Private/Templates/Backend/Overview/Index.html
  52. 48
      Tests/Functional/Domain/Import/ImporterTest.php
  53. 91
      Tests/Unit/Domain/Import/Converter/OrganisationTest.php
  54. 108
      Tests/Unit/Domain/Import/Converter/RegistryTest.php
  55. 199
      Tests/Unit/Domain/Import/Converter/TouristInformationTest.php
  56. 141
      Tests/Unit/Domain/Import/Converter/TownTest.php
  57. 118
      Tests/Unit/Domain/Import/Importer/FetchDataTest.php
  58. 243
      Tests/Unit/Domain/Import/ImporterTest.php
  59. 183
      Tests/Unit/Domain/Import/Model/GenericEntityTest.php
  60. 54
      Tests/Unit/Domain/Import/RequestFactoryTest.php
  61. 92
      Tests/Unit/Domain/Import/UrlProvider/RegistryTest.php
  62. 95
      Tests/Unit/Domain/Import/UrlProvider/StaticUrlProviderTest.php
  63. 42
      Tests/Unit/ExtensionTest.php
  64. 24
      composer.json
  65. 15
      ecs.php
  66. 5
      ext_tables.php
  67. 42
      ext_tables.sql
  68. 9
      ext_typoscript_setup.typoscript
  69. 36
      phpunit.xml.dist

@ -0,0 +1,59 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Controller\Backend;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use TYPO3\CMS\Backend\View\BackendTemplateView;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
use WerkraumMedia\ThueCat\View\Backend\Menu;
abstract class AbstractController extends ActionController
{
/**
* BackendTemplateContainer
*
* @var BackendTemplateView
*/
protected $view;
/**
* Backend Template Container
*
* @var string
*/
protected $defaultViewObjectName = BackendTemplateView::class;
protected function initializeView(ViewInterface $view)
{
if ($view instanceof BackendTemplateView) {
$this->getMenu()->addMenu(
$view->getModuleTemplate()->getDocHeaderComponent()->getMenuRegistry(),
$this->uriBuilder,
get_class($this)
);
}
}
abstract protected function getMenu(): Menu;
}

@ -0,0 +1,80 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Controller\Backend;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use WerkraumMedia\ThueCat\Domain\Import\Importer;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration;
use WerkraumMedia\ThueCat\Domain\Repository\Backend\ImportLogRepository;
use WerkraumMedia\ThueCat\Extension;
use WerkraumMedia\ThueCat\Typo3Wrapper\TranslationService;
use WerkraumMedia\ThueCat\View\Backend\Menu;
class ImportController extends AbstractController
{
private Importer $importer;
private ImportLogRepository $repository;
private TranslationService $translation;
private Menu $menu;
public function __construct(
Importer $importer,
ImportLogRepository $repository,
TranslationService $translation,
Menu $menu
) {
$this->importer = $importer;
$this->repository = $repository;
$this->translation = $translation;
$this->menu = $menu;
}
public function indexAction(): void
{
$this->view->assignMultiple([
'imports' => $this->repository->findAll(),
]);
}
public function importAction(ImportConfiguration $importConfiguration): void
{
$this->importer->importConfiguration($importConfiguration);
$this->addFlashMessage(
$this->translation->translate(
'controller.backend.import.import.success.text',
Extension::EXTENSION_NAME,
[$importConfiguration->getTitle()]
),
$this->translation->translate(
'controller.backend.import.import.success.title',
Extension::EXTENSION_NAME
)
);
$this->redirect('index', 'Backend\Overview');
}
protected function getMenu(): Menu
{
return $this->menu;
}
}

@ -0,0 +1,58 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Controller\Backend;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use WerkraumMedia\ThueCat\Domain\Repository\Backend\ImportConfigurationRepository;
use WerkraumMedia\ThueCat\Domain\Repository\Backend\OrganisationRepository;
use WerkraumMedia\ThueCat\View\Backend\Menu;
class OverviewController extends AbstractController
{
private OrganisationRepository $organisationRepository;
private ImportConfigurationRepository $importConfigurationRepository;
private Menu $menu;
public function __construct(
OrganisationRepository $organisationRepository,
ImportConfigurationRepository $importConfigurationRepository,
Menu $menu
) {
$this->organisationRepository = $organisationRepository;
$this->importConfigurationRepository = $importConfigurationRepository;
$this->menu = $menu;
}
public function indexAction(): void
{
$this->view->assignMultiple([
'importConfigurations' => $this->importConfigurationRepository->findAll(),
'organisations' => $this->organisationRepository->findAll(),
]);
}
protected function getMenu(): Menu
{
return $this->menu;
}
}

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\DependencyInjection;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use WerkraumMedia\ThueCat\Domain\Import\Converter\Registry;
class ConverterPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$registry = $container->findDefinition(Registry::class);
foreach ($container->findTaggedServiceIds('thuecat.converter') as $id => $tags) {
$definition = $container->findDefinition($id);
if (!$definition->isAutoconfigured() || $definition->isAbstract()) {
continue;
}
// Services that implement MyCustomInterface need to be public,
// to be lazy loadable by the registry via $container->get()
// $container->findDefinition($id)->setPublic(true);
$registry->addMethodCall('registerConverter', [$definition]);
}
}
}

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\DependencyInjection;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use WerkraumMedia\ThueCat\Domain\Import\UrlProvider\Registry;
class UrlProvidersPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$registry = $container->findDefinition(Registry::class);
foreach ($container->findTaggedServiceIds('thuecat.urlprovider') as $id => $tags) {
$definition = $container->findDefinition($id);
if (!$definition->isAutoconfigured() || $definition->isAbstract()) {
continue;
}
// Services that implement MyCustomInterface need to be public,
// to be lazy loadable by the registry via $container->get()
// $container->findDefinition($id)->setPublic(true);
$registry->addMethodCall('registerProvider', [$definition]);
}
}
}

@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Import\Converter;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use WerkraumMedia\ThueCat\Domain\Import\Model\Entity;
interface Converter
{
/**
* A single type is an array of different types.
* All types together identify a specific entity and possible converter.
*/
public function canConvert(array $type): bool;
public function convert(array $jsonIdOfEntity): Entity;
}

@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Import\Converter;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use WerkraumMedia\ThueCat\Domain\Import\Model\GenericEntity;
class Organisation implements Converter
{
public function convert(array $jsonIdOfEntity): GenericEntity
{
return new GenericEntity(
95,
'tx_thuecat_organisation',
$jsonIdOfEntity['@id'],
[
'title' => $jsonIdOfEntity['schema:name']['@value'],
'description' => $jsonIdOfEntity['schema:description']['@value'],
]
);
}
public function canConvert(array $type): bool
{
return array_search('thuecat:TouristMarketingCompany', $type) !== false;
}
}

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Import\Converter;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* Central registry of all available converters.
*/
class Registry
{
private array $converters = [];
public function registerConverter(Converter $converter): void
{
$this->converters[] = $converter;
}
public function getConverterBasedOnType(array $type): ?Converter
{
foreach ($this->converters as $converter) {
if ($converter->canConvert($type)) {
return $converter;
}
}
return null;
}
}

@ -0,0 +1,72 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Import\Converter;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use WerkraumMedia\ThueCat\Domain\Import\Model\GenericEntity;
use WerkraumMedia\ThueCat\Domain\Repository\Backend\OrganisationRepository;
use WerkraumMedia\ThueCat\Domain\Repository\Backend\TownRepository;
class TouristInformation implements Converter
{
private OrganisationRepository $organisationRepository;
private TownRepository $townRepository;
public function __construct(
OrganisationRepository $organisationRepository,
TownRepository $townRepository
) {
$this->organisationRepository = $organisationRepository;
$this->townRepository = $townRepository;
}
public function convert(array $jsonIdOfEntity): GenericEntity
{
$manager = $this->organisationRepository->findOneByRemoteId($jsonIdOfEntity['thuecat:managedBy']['@id']);
$town = $this->townRepository->findOneByRemoteIds($this->getContainedInPlaceIds($jsonIdOfEntity));
return new GenericEntity(
95,
'tx_thuecat_tourist_information',
$jsonIdOfEntity['@id'],
[
'title' => $jsonIdOfEntity['schema:name']['@value'],
'description' => $jsonIdOfEntity['schema:description'][0]['@value'],
'managed_by' => $manager ? $manager->getUid() : 0,
'town' => $town ? $town->getUid() : 0,
]
);
}
public function canConvert(array $type): bool
{
return array_search('thuecat:TouristInformation', $type) !== false;
}
private function getContainedInPlaceIds(array $jsonIdOfEntity): array
{
return array_map(function (array $place) {
return $place['@id'];
}, $jsonIdOfEntity['schema:containedInPlace']);
}
}

@ -0,0 +1,58 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Import\Converter;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use WerkraumMedia\ThueCat\Domain\Import\Model\GenericEntity;
use WerkraumMedia\ThueCat\Domain\Repository\Backend\OrganisationRepository;
class Town implements Converter
{
private OrganisationRepository $organisationRepository;
public function __construct(
OrganisationRepository $organisationRepository
) {
$this->organisationRepository = $organisationRepository;
}
public function convert(array $jsonIdOfEntity): GenericEntity
{
$manager = $this->organisationRepository->findOneByRemoteId($jsonIdOfEntity['thuecat:managedBy']['@id']);
return new GenericEntity(
95,
'tx_thuecat_town',
$jsonIdOfEntity['@id'],
[
'title' => $jsonIdOfEntity['schema:name']['@value'],
'description' => $jsonIdOfEntity['schema:description']['@value'] ?? '',
'managed_by' => $manager ? $manager->getUid() : 0,
]
);
}
public function canConvert(array $type): bool
{
return array_search('thuecat:Town', $type) !== false;
}
}

@ -0,0 +1,93 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Import;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use TYPO3\CMS\Core\Utility\GeneralUtility;
use WerkraumMedia\ThueCat\Domain\Import\Converter\Converter;
use WerkraumMedia\ThueCat\Domain\Import\Converter\Registry as ConverterRegistry;
use WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData;
use WerkraumMedia\ThueCat\Domain\Import\Importer\SaveData;
use WerkraumMedia\ThueCat\Domain\Import\UrlProvider\Registry as UrlProviderRegistry;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLog;
use WerkraumMedia\ThueCat\Domain\Repository\Backend\ImportLogRepository;
class Importer
{
private UrlProviderRegistry $urls;
private ConverterRegistry $converter;
private FetchData $fetchData;
private SaveData $saveData;
private ImportLog $importLog;
private ImportLogRepository $importLogRepository;
public function __construct(
UrlProviderRegistry $urls,
ConverterRegistry $converter,
ImportLogRepository $importLogRepository,
FetchData $fetchData,
SaveData $saveData
) {
$this->urls = $urls;
$this->converter = $converter;
$this->importLogRepository = $importLogRepository;
$this->fetchData = $fetchData;
$this->saveData = $saveData;
}
public function importConfiguration(ImportConfiguration $configuration): ImportLog
{
$this->importLog = GeneralUtility::makeInstance(ImportLog::class, $configuration);
$urlProvider = $this->urls->getProviderForConfiguration($configuration);
foreach ($urlProvider->getUrls() as $url) {
$this->importResourceByUrl($url);
}
$this->importLogRepository->addLog($this->importLog);
return clone $this->importLog;
}
private function importResourceByUrl(string $url): void
{
$content = $this->fetchData->jsonLDFromUrl($url);
if ($content === []) {
return;
}
foreach ($content['@graph'] as $jsonEntity) {
$this->importJsonEntity($jsonEntity);
}
}
private function importJsonEntity(array $jsonEntity): void
{
$converter = $this->converter->getConverterBasedOnType($jsonEntity['@type']);
if ($converter instanceof Converter) {
$this->saveData->import($converter->convert($jsonEntity), $this->importLog);
return;
}
}
}

@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Import\Importer;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
class FetchData
{
public function __construct(
RequestFactoryInterface $requestFactory,
ClientInterface $httpClient
) {
$this->requestFactory = $requestFactory;
$this->httpClient = $httpClient;
}
public function jsonLDFromUrl(string $url): array
{
$request = $this->requestFactory->createRequest('GET', $url);
$response = $this->httpClient->sendRequest($request);
$json = json_decode((string) $response->getBody(), true);
if (is_array($json)) {
return $json;
}
return [];
}
}

@ -0,0 +1,102 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Import\Importer;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\DataHandling\DataHandler;
use WerkraumMedia\ThueCat\Domain\Import\Model\Entity;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLog;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLogEntry;
class SaveData
{
private DataHandler $dataHandler;
private ConnectionPool $connectionPool;
public function __construct(
DataHandler $dataHandler,
ConnectionPool $connectionPool
) {
$this->dataHandler = $dataHandler;
$this->dataHandler->stripslashes_values = 0;
$this->connectionPool = $connectionPool;
}
public function import(Entity $entity, ImportLog $log): void
{
$dataHandler = clone $this->dataHandler;
$identifier = $this->getIdentifier($entity);
$dataHandler->start([
$entity->getTypo3DatabaseTableName() => [
$identifier => array_merge($entity->getData(), [
'pid' => $entity->getTypo3StoragePid(),
'remote_id' => $entity->getRemoteId(),
]),
],
], []);
$dataHandler->process_datamap();
if (isset($dataHandler->substNEWwithIDs[$identifier])) {
$entity->setImportedTypo3Uid($dataHandler->substNEWwithIDs[$identifier]);
} elseif (is_numeric($identifier)) {
$entity->setExistingTypo3Uid((int) $identifier);
}
$log->addEntry(new ImportLogEntry(
$entity,
$dataHandler->errorLog
));
}
private function getIdentifier(Entity $entity): string
{
$existingUid = $this->getExistingUid($entity);
if ($existingUid > 0) {
return (string) $existingUid;
}
return 'NEW_1';
}
private function getExistingUid(Entity $entity): int
{
$queryBuilder = $this->connectionPool->getQueryBuilderForTable($entity->getTypo3DatabaseTableName());
$queryBuilder->getRestrictions()->removeAll();
$queryBuilder->select('uid');
$queryBuilder->from($entity->getTypo3DatabaseTableName());
$queryBuilder->where($queryBuilder->expr()->eq(
'remote_id',
$queryBuilder->createNamedParameter($entity->getRemoteId())
));
$result = $queryBuilder->execute()->fetchColumn();
if (is_numeric($result)) {
return (int) $result;
}
return 0;
}
}

@ -0,0 +1,65 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Import\Model;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
interface Entity
{
public function getTypo3StoragePid(): int;
public function getTypo3DatabaseTableName(): string;
/**
* Return full remote id as delivered by remote API.
*/
public function getRemoteId(): string;
/**
* Return db_column_name => db_value.
*/
public function getData(): array;
/**
* Might be called during import.
* Only in case entitiy already existed.
* Is then called with existing UID from system.
*/
public function setExistingTypo3Uid(int $uid): void;
/**
* Might be called during import.
* Only in case entitiy didn't exist within system.
* Is then called with new UID from system.
*/
public function setImportedTypo3Uid(int $uid): void;
/**
* Should be 0 if no uid is known.
*/
public function getTypo3Uid(): int;
/**
* Must return true in case the entitiy did not exist.
*/
public function wasCreated(): bool;
}

@ -0,0 +1,88 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Import\Model;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
class GenericEntity implements Entity
{
private int $typo3StoragePid;
private string $typo3DatabaseTableName;
private bool $created = false;
private int $typo3Uid = 0;
private string $remoteId;
private array $data;
public function __construct(
int $typo3StoragePid,
string $typo3DatabaseTableName,
string $remoteId,
array $data
) {
$this->typo3StoragePid = $typo3StoragePid;
$this->typo3DatabaseTableName = $typo3DatabaseTableName;
$this->remoteId = $remoteId;
$this->data = $data;
}
public function getTypo3StoragePid(): int
{
return $this->typo3StoragePid;
}
public function getTypo3DatabaseTableName(): string
{
return $this->typo3DatabaseTableName;
}
public function getRemoteId(): string
{
return $this->remoteId;
}
public function getData(): array
{
return $this->data;
}
public function setImportedTypo3Uid(int $uid): void
{
$this->typo3Uid = $uid;
$this->created = true;
}
public function setExistingTypo3Uid(int $uid): void
{
$this->typo3Uid = $uid;
$this->created = false;
}
public function getTypo3Uid(): int
{
return $this->typo3Uid;
}
public function wasCreated(): bool
{
return $this->created;
}
}

@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Import;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use Psr\Http\Message\RequestInterface;
use TYPO3\CMS\Core\Http\RequestFactory as Typo3RequestFactory;
use TYPO3\CMS\Core\Http\Uri;
class RequestFactory extends Typo3RequestFactory
{
public function createRequest(string $method, $uri): RequestInterface
{
$uri = new Uri($uri);
$uri = $uri->withQuery('?format=jsonId');
// TODO: Add api key from site
return parent::createRequest($method, $uri);
}
}

@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Import\UrlProvider;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration;
/**
* Central registry of all available url provider.
*/
class Registry
{
private array $provider = [];
public function registerProvider(UrlProvider $provider): void
{
$this->provider[] = $provider;
}
/**
* @return UrlProvider[]
*/
public function getProviderForConfiguration(ImportConfiguration $configuration): ?UrlProvider
{
foreach ($this->provider as $provider) {
if ($provider->canProvideForConfiguration($configuration)) {
return $provider->createWithConfiguration($configuration);
}
}
return null;
}
}

@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Import\UrlProvider;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use TYPO3\CMS\Core\Utility\GeneralUtility;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration;
class StaticUrlProvider implements UrlProvider
{
private array $urls = [];
public function __construct(
ImportConfiguration $configuration
) {
if ($configuration instanceof ImportConfiguration) {
$this->urls = $configuration->getUrls();
}
}
public function canProvideForConfiguration(
ImportConfiguration $configuration
): bool {
return $configuration->getType() === 'static';
}
public function createWithConfiguration(
ImportConfiguration $configuration
): UrlProvider {
return GeneralUtility::makeInstance(self::class, $configuration);
}
public function getUrls(): array
{
return $this->urls;
}
}

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Import\UrlProvider;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration;
interface UrlProvider
{
/**
* @var string[]
*/
public function getUrls(): array;
public function canProvideForConfiguration(ImportConfiguration $configuration): bool;
public function createWithConfiguration(ImportConfiguration $configuration): UrlProvider;
}

@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Model\Backend;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity as Typo3AbstractEntity;
class AbstractEntity extends Typo3AbstractEntity
{
protected string $remoteId = '';
protected string $title = '';
protected string $description = '';
protected ?\DateTimeImmutable $tstamp = null;
public function getRemoteId(): string
{
return $this->remoteId;
}
public function getTitle(): string
{
return $this->title;
}
public function getDescription(): string
{
return $this->description;
}
public function getLastImported(): ?\DateTimeImmutable
{
return $this->tstamp;
}
}

@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Model\Backend;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use TYPO3\CMS\Core\Utility\ArrayUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
class ImportConfiguration extends AbstractEntity
{
protected string $title = '';
protected string $type = '';
protected string $configuration = '';
protected ?\DateTimeImmutable $tstamp = null;
public function getTitle(): string
{
return $this->title;
}
public function getType(): string
{
return $this->type;
}
public function getTableName(): string
{
return 'tx_thuecat_import_configuration';
}
public function getLastChanged(): ?\DateTimeImmutable
{
return $this->tstamp;
}
public function getUrls(): array
{
if ($this->configuration === '') {
return [];
}
$entries = array_map(function (array $urlEntry) {
return ArrayUtility::getValueByPath($urlEntry, 'url/el/url/vDEF');
}, $this->getEntries());
return array_values($entries);
}
private function getEntries(): array
{
return ArrayUtility::getValueByPath(
GeneralUtility::xml2array($this->configuration),
'data/sDEF/lDEF/urls/el'
);
}
}

@ -0,0 +1,114 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Model\Backend;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity as Typo3AbstractEntity;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
class ImportLog extends Typo3AbstractEntity
{
/**
* @var ObjectStorage<ImportLogEntry>
*/
protected $logEntries = [];
/**
* @var ImportConfiguration
*/
protected $configuration;
/**
* @var \DateTimeImmutable|null
*/
protected $crdate;
public function __construct(
ImportConfiguration $configuration
) {
$this->logEntries = new ObjectStorage();
$this->configuration = $configuration;
}
public function addEntry(ImportLogEntry $entry): void
{
$this->logEntries->attach($entry);
}
public function getConfiguration(): ImportConfiguration
{
return $this->configuration;
}
/**
* @return ObjectStorage<ImportLogEntry>
*/
public function getEntries(): ObjectStorage
{
return $this->logEntries;
}
public function getCreated(): ?\DateTimeImmutable
{
return $this->crdate;
}
public function getListOfErrors(): array
{
$errors = [];
foreach ($this->getEntries() as $entry) {
if ($entry->hasErrors()) {
$errors = array_merge($errors, $entry->getErrors());
}
}
return $errors;
}
public function hasErrors(): bool
{
foreach ($this->getEntries() as $entry) {
if ($entry->hasErrors()) {
return true;
}
}
return false;
}
public function getSummaryOfEntries(): array
{
$summary = [];
foreach ($this->getEntries() as $entry) {
if (isset($summary[$entry->getRecordDatabaseTableName()])) {
++$summary[$entry->getRecordDatabaseTableName()];
continue;
}
$summary[$entry->getRecordDatabaseTableName()] = 1;
}
return $summary;
}
}

@ -0,0 +1,97 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Model\Backend;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity as Typo3AbstractEntity;
use WerkraumMedia\ThueCat\Domain\Import\Model\Entity;
class ImportLogEntry extends Typo3AbstractEntity
{
/**
* @var bool
*/
protected $insertion = false;
/**
* @var int
*/
protected $recordUid = 0;
/**
* @var int
*/
protected $recordPid = 0;
/**
* @var string
*/
protected $tableName = '';
/**
* @var string
*/
protected $errors = '';
protected array $errorsAsArray = [];
public function __construct(
Entity $entity,
array $dataHandlerErrorLog
) {
$this->insertion = $entity->wasCreated();
$this->recordUid = $entity->getTypo3Uid();
$this->recordPid = $entity->getTypo3StoragePid();
$this->tableName = $entity->getTypo3DatabaseTableName();
$this->errorsAsArray = $dataHandlerErrorLog;
}
public function wasInsertion(): bool
{
return $this->insertion;
}
public function getRecordUid(): int
{
return $this->recordUid;
}
public function getRecordDatabaseTableName(): string
{
return $this->tableName;
}
public function getErrors(): array
{
if ($this->errorsAsArray === [] && $this->errors !== '') {
$this->errorsAsArray = json_decode($this->errors, true);
}
return $this->errorsAsArray;
}
public function hasErrors(): bool
{
return $this->getErrors() !== [];
}
}

@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Model\Backend;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
class Organisation extends AbstractEntity
{
/**
* @var ObjectStorage<Town>
*/
protected $managesTowns;
/**
* @var ObjectStorage<TouristInformation>
*/
protected $managesTouristInformation;
public function getManagesTowns(): ObjectStorage
{
return $this->managesTowns;
}
public function getManagesTouristInformation(): ObjectStorage
{
return $this->managesTouristInformation;
}
public function getTableName(): string
{
return 'tx_thuecat_organisation';
}
}

@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Model\Backend;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
class TouristInformation extends AbstractEntity
{