mirror of
https://github.com/werkraum-media/thuecat.git
synced 2024-12-05 03:26:13 +01:00
Add new import configuration based on containsPlace (#98)
Adds a new type of import configuration. This configuration allows to define a single resource. All the resources referenced via schema:containsPlace will be imported. Relates: #10237
This commit is contained in:
parent
d7c7d8eaee
commit
61ae59c127
16 changed files with 515 additions and 32 deletions
|
@ -23,6 +23,8 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace WerkraumMedia\ThueCat\Domain\Import;
|
namespace WerkraumMedia\ThueCat\Domain\Import;
|
||||||
|
|
||||||
|
use TYPO3\CMS\Core\Log\LogManager;
|
||||||
|
use TYPO3\CMS\Core\Log\Logger;
|
||||||
use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\EntityRegistry;
|
use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\EntityRegistry;
|
||||||
use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\JsonDecode;
|
use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\JsonDecode;
|
||||||
use WerkraumMedia\ThueCat\Domain\Import\Entity\MapsToType;
|
use WerkraumMedia\ThueCat\Domain\Import\Entity\MapsToType;
|
||||||
|
@ -78,6 +80,11 @@ class Importer
|
||||||
*/
|
*/
|
||||||
private $importLogRepository;
|
private $importLogRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Logger
|
||||||
|
*/
|
||||||
|
private $logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Import
|
* @var Import
|
||||||
*/
|
*/
|
||||||
|
@ -91,7 +98,8 @@ class Importer
|
||||||
Languages $languages,
|
Languages $languages,
|
||||||
ImportLogRepository $importLogRepository,
|
ImportLogRepository $importLogRepository,
|
||||||
FetchData $fetchData,
|
FetchData $fetchData,
|
||||||
SaveData $saveData
|
SaveData $saveData,
|
||||||
|
LogManager $logManager
|
||||||
) {
|
) {
|
||||||
$this->urls = $urls;
|
$this->urls = $urls;
|
||||||
$this->converter = $converter;
|
$this->converter = $converter;
|
||||||
|
@ -101,6 +109,7 @@ class Importer
|
||||||
$this->importLogRepository = $importLogRepository;
|
$this->importLogRepository = $importLogRepository;
|
||||||
$this->fetchData = $fetchData;
|
$this->fetchData = $fetchData;
|
||||||
$this->saveData = $saveData;
|
$this->saveData = $saveData;
|
||||||
|
$this->logger = $logManager->getLogger(__CLASS__);
|
||||||
$this->import = new Import();
|
$this->import = new Import();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +120,13 @@ class Importer
|
||||||
$this->import->end();
|
$this->import->end();
|
||||||
|
|
||||||
if ($this->import->done()) {
|
if ($this->import->done()) {
|
||||||
|
$this->logger->info(
|
||||||
|
'Finished import.',
|
||||||
|
[
|
||||||
|
'errors' => $this->import->getLog()->getListOfErrors(),
|
||||||
|
'summary' => $this->import->getLog()->getSummaryOfEntries(),
|
||||||
|
]
|
||||||
|
);
|
||||||
$this->importLogRepository->addLog($this->import->getLog());
|
$this->importLogRepository->addLog($this->import->getLog());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,12 +147,15 @@ class Importer
|
||||||
|
|
||||||
private function importResourceByUrl(string $url): void
|
private function importResourceByUrl(string $url): void
|
||||||
{
|
{
|
||||||
|
$this->logger->info('Process url.', ['url' => $url]);
|
||||||
if ($this->import->handledRemoteId($url)) {
|
if ($this->import->handledRemoteId($url)) {
|
||||||
|
$this->logger->notice('Skip Url as we already handled it during import.', ['url' => $url]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$content = $this->fetchData->jsonLDFromUrl($url);
|
$content = $this->fetchData->jsonLDFromUrl($url);
|
||||||
|
|
||||||
if ($content === []) {
|
if ($content === []) {
|
||||||
|
$this->logger->notice('Skip Url as we did not receive any content.', ['url' => $url]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,12 +172,14 @@ class Importer
|
||||||
|
|
||||||
$targetEntity = $this->entityRegistry->getEntityByTypes($jsonEntity['@type']);
|
$targetEntity = $this->entityRegistry->getEntityByTypes($jsonEntity['@type']);
|
||||||
if ($targetEntity === '') {
|
if ($targetEntity === '') {
|
||||||
|
$this->logger->notice('Skip entity, no target entity found.', ['types' => $jsonEntity['@type']]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$entities = new EntityCollection();
|
$entities = new EntityCollection();
|
||||||
|
|
||||||
foreach ($this->languages->getAvailable($this->import->getConfiguration()) as $language) {
|
foreach ($this->languages->getAvailable($this->import->getConfiguration()) as $language) {
|
||||||
|
$this->logger->info('Process entity for language.', ['language' => $language, 'targetEntity' => $targetEntity]);
|
||||||
$mappedEntity = $this->entityMapper->mapDataToEntity(
|
$mappedEntity = $this->entityMapper->mapDataToEntity(
|
||||||
$jsonEntity,
|
$jsonEntity,
|
||||||
$targetEntity,
|
$targetEntity,
|
||||||
|
@ -167,6 +188,7 @@ class Importer
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
if (!$mappedEntity instanceof MapsToType) {
|
if (!$mappedEntity instanceof MapsToType) {
|
||||||
|
$this->logger->alert('Mapping did not result in an MapsToType instance.', ['class' => get_class($mappedEntity)]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$convertedEntity = $this->converter->convert(
|
$convertedEntity = $this->converter->convert(
|
||||||
|
@ -176,6 +198,7 @@ class Importer
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($convertedEntity === null) {
|
if ($convertedEntity === null) {
|
||||||
|
$this->logger->alert('Could not convert entity.', ['language' => $language, 'targetEntity' => $targetEntity]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$entities->add($convertedEntity);
|
$entities->add($convertedEntity);
|
||||||
|
@ -199,6 +222,7 @@ class Importer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->logger->notice('Deny entity as type is not allowed.', ['types' => $jsonEntity['@type']]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,11 @@ class FetchData
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getFullResourceUrl(string $id): string
|
||||||
|
{
|
||||||
|
return $this->getResourceEndpoint() . ltrim($id, '/');
|
||||||
|
}
|
||||||
|
|
||||||
public function jsonLDFromUrl(string $url): array
|
public function jsonLDFromUrl(string $url): array
|
||||||
{
|
{
|
||||||
$cacheIdentifier = sha1($url);
|
$cacheIdentifier = sha1($url);
|
||||||
|
@ -98,7 +103,7 @@ class FetchData
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getResourceEndpoint(): string
|
private function getResourceEndpoint(): string
|
||||||
{
|
{
|
||||||
return $this->urlPrefix . '/resources/';
|
return $this->urlPrefix . '/resources/';
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Daniel Siepmann <coding@daniel-siepmann.de>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace WerkraumMedia\ThueCat\Domain\Import\UrlProvider;
|
||||||
|
|
||||||
|
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 = '';
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
FetchData $fetchData
|
||||||
|
) {
|
||||||
|
$this->fetchData = $fetchData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canProvideForConfiguration(
|
||||||
|
ImportConfiguration $configuration
|
||||||
|
): bool {
|
||||||
|
return $configuration->getType() === 'containsPlace';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createWithConfiguration(
|
||||||
|
ImportConfiguration $configuration
|
||||||
|
): UrlProvider {
|
||||||
|
if (method_exists($configuration, 'getContainsPlaceId') === false) {
|
||||||
|
throw new \InvalidArgumentException('Received incompatible import configuration.', 1629709276);
|
||||||
|
}
|
||||||
|
$instance = clone $this;
|
||||||
|
$instance->containsPlaceId = $configuration->getContainsPlaceId();
|
||||||
|
|
||||||
|
return $instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUrls(): array
|
||||||
|
{
|
||||||
|
$response = $this->fetchData->jsonLDFromUrl(
|
||||||
|
$this->fetchData->getFullResourceUrl($this->containsPlaceId)
|
||||||
|
);
|
||||||
|
$resources = array_values($response['@graph'][0]['schema:containsPlace'] ?? []);
|
||||||
|
|
||||||
|
return array_map(function (array $resource) {
|
||||||
|
return $resource['@id'] ?? '';
|
||||||
|
}, $resources);
|
||||||
|
}
|
||||||
|
}
|
|
@ -65,13 +65,10 @@ class SyncScopeUrlProvider implements UrlProvider
|
||||||
public function getUrls(): array
|
public function getUrls(): array
|
||||||
{
|
{
|
||||||
$response = $this->fetchData->updatedNodes($this->syncScopeId);
|
$response = $this->fetchData->updatedNodes($this->syncScopeId);
|
||||||
|
|
||||||
$resourceIds = array_values($response['data']['createdOrUpdated'] ?? []);
|
$resourceIds = array_values($response['data']['createdOrUpdated'] ?? []);
|
||||||
|
|
||||||
$urls = array_map(function (string $id) {
|
return array_map(function (string $id) {
|
||||||
return $this->fetchData->getResourceEndpoint() . $id;
|
return $this->fetchData->getFullResourceUrl($id);
|
||||||
}, $resourceIds);
|
}, $resourceIds);
|
||||||
|
|
||||||
return $urls;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,14 +106,7 @@ class ImportConfiguration extends AbstractEntity implements ImportConfigurationI
|
||||||
|
|
||||||
public function getStoragePid(): int
|
public function getStoragePid(): int
|
||||||
{
|
{
|
||||||
if ($this->configuration === '') {
|
$storagePid = $this->getConfigurationValueFromFlexForm('storagePid');
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$storagePid = ArrayUtility::getValueByPath(
|
|
||||||
GeneralUtility::xml2array($this->configuration),
|
|
||||||
'data/sDEF/lDEF/storagePid/vDEF'
|
|
||||||
);
|
|
||||||
|
|
||||||
if (is_numeric($storagePid) && $storagePid > 0) {
|
if (is_numeric($storagePid) && $storagePid > 0) {
|
||||||
return intval($storagePid);
|
return intval($storagePid);
|
||||||
|
@ -148,21 +141,16 @@ class ImportConfiguration extends AbstractEntity implements ImportConfigurationI
|
||||||
|
|
||||||
public function getSyncScopeId(): string
|
public function getSyncScopeId(): string
|
||||||
{
|
{
|
||||||
if ($this->configuration === '') {
|
return $this->getConfigurationValueFromFlexForm('syncScopeId');
|
||||||
return '';
|
}
|
||||||
|
|
||||||
|
public function getContainsPlaceId(): string
|
||||||
|
{
|
||||||
|
$containsPlaceId = $this->getConfigurationValueFromFlexForm('containsPlaceId');
|
||||||
|
if (!is_string($containsPlaceId)) {
|
||||||
|
throw new \Exception('Could not fetch containsPlaceId.', 1671027015);
|
||||||
}
|
}
|
||||||
|
return $containsPlaceId;
|
||||||
$configurationAsArray = $this->getConfigurationAsArray();
|
|
||||||
$arrayPath = 'data/sDEF/lDEF/syncScopeId/vDEF';
|
|
||||||
|
|
||||||
if (ArrayUtility::isValidPath($configurationAsArray, $arrayPath) === false) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return ArrayUtility::getValueByPath(
|
|
||||||
$configurationAsArray,
|
|
||||||
$arrayPath
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getEntries(): array
|
private function getEntries(): array
|
||||||
|
@ -198,4 +186,26 @@ class ImportConfiguration extends AbstractEntity implements ImportConfigurationI
|
||||||
$configuration->allowedTypes = $allowedTypes;
|
$configuration->allowedTypes = $allowedTypes;
|
||||||
return $configuration;
|
return $configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
private function getConfigurationValueFromFlexForm(string $fieldName)
|
||||||
|
{
|
||||||
|
if ($this->configuration === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$configurationAsArray = $this->getConfigurationAsArray();
|
||||||
|
$arrayPath = 'data/sDEF/lDEF/' . $fieldName . '/vDEF';
|
||||||
|
|
||||||
|
if (ArrayUtility::isValidPath($configurationAsArray, $arrayPath) === false) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return ArrayUtility::getValueByPath(
|
||||||
|
$configurationAsArray,
|
||||||
|
$arrayPath
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
36
Configuration/FlexForm/ImportConfiguration/ContainsPlace.xml
Normal file
36
Configuration/FlexForm/ImportConfiguration/ContainsPlace.xml
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<T3DataStructure>
|
||||||
|
<meta>
|
||||||
|
<langDisable>1</langDisable>
|
||||||
|
</meta>
|
||||||
|
<sheets>
|
||||||
|
<sDEF>
|
||||||
|
<ROOT>
|
||||||
|
<TCEforms>
|
||||||
|
<sheetTitle>LLL:EXT:thuecat/Resources/Private/Language/locallang_flexform.xlf:importConfiguration.containsPlace.sheetTitle</sheetTitle>
|
||||||
|
</TCEforms>
|
||||||
|
<type>array</type>
|
||||||
|
<el>
|
||||||
|
<storagePid>
|
||||||
|
<TCEforms>
|
||||||
|
<label>LLL:EXT:thuecat/Resources/Private/Language/locallang_flexform.xlf:importConfiguration.containsPlace.storagePid</label>
|
||||||
|
<config>
|
||||||
|
<type>input</type>
|
||||||
|
<eval>int,required</eval>
|
||||||
|
</config>
|
||||||
|
</TCEforms>
|
||||||
|
</storagePid>
|
||||||
|
<containsPlaceId>
|
||||||
|
<TCEforms>
|
||||||
|
<label>LLL:EXT:thuecat/Resources/Private/Language/locallang_flexform.xlf:importConfiguration.containsPlace.containsPlaceId</label>
|
||||||
|
<description>LLL:EXT:thuecat/Resources/Private/Language/locallang_flexform.xlf:importConfiguration.containsPlace.containsPlaceId.description</description>
|
||||||
|
<config>
|
||||||
|
<type>input</type>
|
||||||
|
<eval>trim,required</eval>
|
||||||
|
</config>
|
||||||
|
</TCEforms>
|
||||||
|
</containsPlaceId>
|
||||||
|
</el>
|
||||||
|
</ROOT>
|
||||||
|
</sDEF>
|
||||||
|
</sheets>
|
||||||
|
</T3DataStructure>
|
|
@ -45,6 +45,10 @@ return (static function (string $extensionKey, string $tableName) {
|
||||||
$languagePath . '.type.syncScope',
|
$languagePath . '.type.syncScope',
|
||||||
'syncScope',
|
'syncScope',
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
$languagePath . '.type.containsPlace',
|
||||||
|
'containsPlace',
|
||||||
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -57,6 +61,7 @@ return (static function (string $extensionKey, string $tableName) {
|
||||||
'default' => $flexFormConfigurationPath . 'ImportConfiguration/Static.xml',
|
'default' => $flexFormConfigurationPath . 'ImportConfiguration/Static.xml',
|
||||||
'static' => $flexFormConfigurationPath . 'ImportConfiguration/Static.xml',
|
'static' => $flexFormConfigurationPath . 'ImportConfiguration/Static.xml',
|
||||||
'syncScope' => $flexFormConfigurationPath . 'ImportConfiguration/SyncScope.xml',
|
'syncScope' => $flexFormConfigurationPath . 'ImportConfiguration/SyncScope.xml',
|
||||||
|
'containsPlace' => $flexFormConfigurationPath . 'ImportConfiguration/ContainsPlace.xml',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
|
@ -13,6 +13,10 @@ Features
|
||||||
|
|
||||||
* Last import date is now shown within backend module beside each import configuration.
|
* Last import date is now shown within backend module beside each import configuration.
|
||||||
|
|
||||||
|
* New import configuration type "Contains Place".
|
||||||
|
This allows to provide a single entity, e.g. a Town that has multiple ``schema:containsPlace`` entries.
|
||||||
|
Each of them will be imported.
|
||||||
|
|
||||||
* Import author of media. This allows to either render the license author or the author.
|
* Import author of media. This allows to either render the license author or the author.
|
||||||
|
|
||||||
* Filter and sort opening hours.
|
* Filter and sort opening hours.
|
||||||
|
|
|
@ -28,6 +28,20 @@
|
||||||
<source>syncScopeId</source>
|
<source>syncScopeId</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|
||||||
|
<!-- Contains Place Import Configuration -->
|
||||||
|
<trans-unit id="importConfiguration.containsPlace.sheetTitle" xml:space="preserve">
|
||||||
|
<source>Contains place import configuration</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="importConfiguration.containsPlace.storagePid" xml:space="preserve">
|
||||||
|
<source>Storage Page UID</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="importConfiguration.containsPlace.containsPlaceId" xml:space="preserve">
|
||||||
|
<source>Contains Place ID</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="importConfiguration.containsPlace.containsPlaceId.description" xml:space="preserve">
|
||||||
|
<source>Only ID, not full URL e.g. 043064193523-jcyt</source>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
<trans-unit id="pages.tourist_attraction.sheetTitle" xml:space="preserve">
|
<trans-unit id="pages.tourist_attraction.sheetTitle" xml:space="preserve">
|
||||||
<source>Tourist Attraction</source>
|
<source>Tourist Attraction</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|
|
@ -242,6 +242,9 @@
|
||||||
<trans-unit id="tx_thuecat_import_configuration.type.syncScope" xml:space="preserve">
|
<trans-unit id="tx_thuecat_import_configuration.type.syncScope" xml:space="preserve">
|
||||||
<source>Synchronization area</source>
|
<source>Synchronization area</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="tx_thuecat_import_configuration.type.containsPlace" xml:space="preserve">
|
||||||
|
<source>Contains Place</source>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="tx_thuecat_import_configuration.configuration" xml:space="preserve">
|
<trans-unit id="tx_thuecat_import_configuration.configuration" xml:space="preserve">
|
||||||
<source>Configuration</source>
|
<source>Configuration</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|
|
@ -0,0 +1,182 @@
|
||||||
|
{
|
||||||
|
"@context": {
|
||||||
|
"cdb": "https://thuecat.org/ontology/cdb/1.0/",
|
||||||
|
"dachkg": "https://thuecat.org/ontology/dachkg/1.0/",
|
||||||
|
"dbo": "http://dbpedia.org/ontology/",
|
||||||
|
"dsv": "http://ontologies.sti-innsbruck.at/dsv/",
|
||||||
|
"foaf": "http://xmlns.com/foaf/0.1/",
|
||||||
|
"owl": "http://www.w3.org/2002/07/owl#",
|
||||||
|
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
|
||||||
|
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
|
||||||
|
"schema": "http://schema.org/",
|
||||||
|
"sh": "http://www.w3.org/ns/shacl#",
|
||||||
|
"thuecat": "https://thuecat.org/ontology/thuecat/1.0/",
|
||||||
|
"ttgds": "https://thuecat.org/ontology/ttgds/1.0/",
|
||||||
|
"xsd": "http://www.w3.org/2001/XMLSchema#"
|
||||||
|
},
|
||||||
|
"@graph": [
|
||||||
|
{
|
||||||
|
"@id": "https://thuecat.org/resources/043064193523-contains",
|
||||||
|
"@type": [
|
||||||
|
"schema:AdministrativeArea",
|
||||||
|
"schema:Place",
|
||||||
|
"schema:Thing",
|
||||||
|
"schema:City",
|
||||||
|
"ttgds:Destination",
|
||||||
|
"thuecat:Town"
|
||||||
|
],
|
||||||
|
"schema:address": {
|
||||||
|
"@id": "genid-c3843c2db4f74da2bc4a1785b63143b2-b0",
|
||||||
|
"@type": [
|
||||||
|
"schema:Intangible",
|
||||||
|
"schema:PostalAddress",
|
||||||
|
"schema:StructuredValue",
|
||||||
|
"schema:Thing",
|
||||||
|
"schema:ContactPoint"
|
||||||
|
],
|
||||||
|
"schema:addressCountry": {
|
||||||
|
"@type": "thuecat:AddressCountry",
|
||||||
|
"@value": "thuecat:Germany"
|
||||||
|
},
|
||||||
|
"schema:addressLocality": {
|
||||||
|
"@language": "de",
|
||||||
|
"@value": "Erfurt"
|
||||||
|
},
|
||||||
|
"schema:addressRegion": {
|
||||||
|
"@type": "thuecat:AddressFederalState",
|
||||||
|
"@value": "thuecat:Thuringia"
|
||||||
|
},
|
||||||
|
"schema:postalCode": {
|
||||||
|
"@language": "de",
|
||||||
|
"@value": "99084"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schema:containsPlace": [
|
||||||
|
{
|
||||||
|
"@id": "https://thuecat.org/resources/835224016581-dara"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@id": "https://thuecat.org/resources/165868194223-zmqf"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@id": "https://thuecat.org/resources/215230952334-yyno"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"schema:description": [
|
||||||
|
{
|
||||||
|
"@language": "de",
|
||||||
|
"@value": "Kr\u00e4merbr\u00fccke, Dom, Alte Synagoge \u2013 die Th\u00fcringer Landeshauptstadt Erfurt hat viele Kultursch\u00e4tze. Und ein wunderbar junges, studentisches Flair.Eine gute Mischung f\u00fcr alle, die beim Schlendern und Bummeln gerne St\u00e4dte entdecken: Denn in Erfurt findet man einen wunderbaren mittelalterlichen Stadtkern \u2013 mit vielen netten L\u00e4den, Caf\u00e8s und Restaurants. Urlauber wie Einheimische bummeln durch die Gassen der Altstadt, aus allen Ecken wispern Geschichte und alte Geschichten. Stolze historische B\u00fcgerh\u00e4user bilden eine der sch\u00f6nsten Altst\u00e4dte Europas, mittendrin das neugotische Rathaus aus den 1870er-Jahren am Fischmarkt, die spitzt\u00fcrmige St. Severikirche und der m\u00e4chtige Dom, 1117 erstmals urkundlich erw\u00e4hnt \u2013 auf seiner schier endlosen, kaskadenf\u00f6rmigen 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\u00e8 Hilgenfeld), in die Wein-Destille am benachbarten Petersberg oder in eins der l\u00e4ssigen Restaurants (Tipp: Mathilda oder Ballenberger), wo zum freundlichen Miteinander eine frische und moderne K\u00fcche serviert wird.In Erfurt pulsiert das Leben, lassen Sie sich einfach treiben. Von Ihrer Neugierde ..."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@id": "genid-c3843c2db4f74da2bc4a1785b63143b2-b1",
|
||||||
|
"@type": [
|
||||||
|
"thuecat:Html"
|
||||||
|
],
|
||||||
|
"schema:value": {
|
||||||
|
"@language": "de",
|
||||||
|
"@value": "Kr\u00e4merbr\u00fccke, Dom, Alte Synagoge \u2013 die Th\u00fcringer Landeshauptstadt Erfurt hat viele Kultursch\u00e4tze. Und ein wunderbar junges, studentisches Flair.Eine gute Mischung f\u00fcr alle, die beim Schlendern und Bummeln gerne St\u00e4dte entdecken: Denn in Erfurt findet man einen wunderbaren mittelalterlichen Stadtkern \u2013 mit vielen netten L\u00e4den, Caf\u00e8s und Restaurants. Urlauber wie Einheimische bummeln durch die Gassen der Altstadt, aus allen Ecken wispern Geschichte und alte Geschichten. Stolze historische B\u00fcgerh\u00e4user bilden eine der sch\u00f6nsten Altst\u00e4dte Europas, mittendrin das neugotische Rathaus aus den 1870er-Jahren am Fischmarkt, die spitzt\u00fcrmige St. Severikirche und der m\u00e4chtige Dom, 1117 erstmals urkundlich erw\u00e4hnt \u2013 auf seiner schier endlosen, kaskadenf\u00f6rmigen 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\u00e8 Hilgenfeld), in die Wein-Destille am benachbarten Petersberg oder in eins der l\u00e4ssigen Restaurants (Tipp: Mathilda oder Ballenberger), wo zum freundlichen Miteinander eine frische und moderne K\u00fcche serviert wird.In Erfurt pulsiert das Leben, lassen Sie sich einfach treiben. Von Ihrer Neugierde ..."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"schema:geo": {
|
||||||
|
"@id": "genid-c3843c2db4f74da2bc4a1785b63143b2-b2",
|
||||||
|
"@type": [
|
||||||
|
"schema:Intangible",
|
||||||
|
"schema:StructuredValue",
|
||||||
|
"schema:Thing",
|
||||||
|
"schema:GeoCoordinates"
|
||||||
|
],
|
||||||
|
"schema:latitude": {
|
||||||
|
"@type": "schema:Number",
|
||||||
|
"@value": "50.97658847089682"
|
||||||
|
},
|
||||||
|
"schema:longitude": {
|
||||||
|
"@type": "schema:Number",
|
||||||
|
"@value": "11.02752685546875"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schema:hasMap": {
|
||||||
|
"@type": "schema:URL",
|
||||||
|
"@value": "https://www.google.com/maps/search/?api=1&query=11.02752685546875,11.02752685546875"
|
||||||
|
},
|
||||||
|
"schema:identifier": [
|
||||||
|
{
|
||||||
|
"@type": "schema:URL",
|
||||||
|
"@value": "https://www.thueringen-entdecken.de/urlaub-hotel-reisen/erfurt-102097.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@id": "genid-c3843c2db4f74da2bc4a1785b63143b2-b3",
|
||||||
|
"@type": [
|
||||||
|
"schema:Intangible",
|
||||||
|
"schema:StructuredValue",
|
||||||
|
"schema:Thing",
|
||||||
|
"schema:PropertyValue"
|
||||||
|
],
|
||||||
|
"schema:name": {
|
||||||
|
"@language": "de",
|
||||||
|
"@value": "TOMASID"
|
||||||
|
},
|
||||||
|
"schema:value": {
|
||||||
|
"@language": "de",
|
||||||
|
"@value": "TTG00020050000218774"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"schema:name": {
|
||||||
|
"@language": "de",
|
||||||
|
"@value": "Erfurt"
|
||||||
|
},
|
||||||
|
"schema:sameAs": {
|
||||||
|
"@type": "schema:URL",
|
||||||
|
"@value": "http://www.erfurt-tourismus.de"
|
||||||
|
},
|
||||||
|
"schema:url": {
|
||||||
|
"@type": "schema:URL",
|
||||||
|
"@value": "http://www.erfurt-tourismus.de"
|
||||||
|
},
|
||||||
|
"thuecat:contentResponsible": {
|
||||||
|
"@id": "https://thuecat.org/resources/018132452787-ngbe"
|
||||||
|
},
|
||||||
|
"thuecat:destinationManagementOrganisation": {
|
||||||
|
"@id": "https://thuecat.org/resources/018132452787-ngbe"
|
||||||
|
},
|
||||||
|
"thuecat:managedBy": {
|
||||||
|
"@id": "https://thuecat.org/resources/018132452787-ngbe"
|
||||||
|
},
|
||||||
|
"thuecat:monumentEnum": {
|
||||||
|
"@type": "thuecat:MonumentEnum",
|
||||||
|
"@value": "thuecat:ZeroInformationMemorialClass"
|
||||||
|
},
|
||||||
|
"thuecat:regionalKey": {
|
||||||
|
"@language": "de",
|
||||||
|
"@value": "160510000000"
|
||||||
|
},
|
||||||
|
"thuecat:tomasLocationID": {
|
||||||
|
"@language": "de",
|
||||||
|
"@value": "TTG00020050000218774"
|
||||||
|
},
|
||||||
|
"thuecat:trafficConnection": [
|
||||||
|
{
|
||||||
|
"@type": "thuecat:TrafficConnection",
|
||||||
|
"@value": "thuecat:BusRoute"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "thuecat:TrafficConnection",
|
||||||
|
"@value": "thuecat:RoadConnection"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "thuecat:TrafficConnection",
|
||||||
|
"@value": "thuecat:RailwayStationEnuMem"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "thuecat:TrafficConnection",
|
||||||
|
"@value": "thuecat:MotorwayConnection"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "thuecat:TrafficConnection",
|
||||||
|
"@value": "thuecat:Airport"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
16
Tests/Functional/Fixtures/Import/ImportsContainsPlace.csv
Normal file
16
Tests/Functional/Fixtures/Import/ImportsContainsPlace.csv
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
"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",
|
|
64
Tests/Functional/Fixtures/Import/ImportsContainsPlace.xml
Normal file
64
Tests/Functional/Fixtures/Import/ImportsContainsPlace.xml
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<dataset>
|
||||||
|
<pages>
|
||||||
|
<uid>1</uid>
|
||||||
|
<pid>0</pid>
|
||||||
|
<tstamp>1613400587</tstamp>
|
||||||
|
<crdate>1613400558</crdate>
|
||||||
|
<cruser_id>1</cruser_id>
|
||||||
|
<doktype>4</doktype>
|
||||||
|
<title>Rootpage</title>
|
||||||
|
<is_siteroot>1</is_siteroot>
|
||||||
|
</pages>
|
||||||
|
<pages>
|
||||||
|
<uid>10</uid>
|
||||||
|
<pid>1</pid>
|
||||||
|
<tstamp>1613400587</tstamp>
|
||||||
|
<crdate>1613400558</crdate>
|
||||||
|
<cruser_id>1</cruser_id>
|
||||||
|
<doktype>254</doktype>
|
||||||
|
<title>Storage folder</title>
|
||||||
|
</pages>
|
||||||
|
|
||||||
|
<sys_language>
|
||||||
|
<uid>1</uid>
|
||||||
|
<pid>0</pid>
|
||||||
|
<title>English</title>
|
||||||
|
<flag>en-us-gb</flag>
|
||||||
|
<language_isocode>en</language_isocode>
|
||||||
|
</sys_language>
|
||||||
|
|
||||||
|
<sys_language>
|
||||||
|
<uid>2</uid>
|
||||||
|
<pid>0</pid>
|
||||||
|
<title>French</title>
|
||||||
|
<flag>fr</flag>
|
||||||
|
<language_isocode>fr</language_isocode>
|
||||||
|
</sys_language>
|
||||||
|
|
||||||
|
<tx_thuecat_import_configuration>
|
||||||
|
<uid>1</uid>
|
||||||
|
<pid>0</pid>
|
||||||
|
<tstamp>1613400587</tstamp>
|
||||||
|
<crdate>1613400558</crdate>
|
||||||
|
<cruser_id>1</cruser_id>
|
||||||
|
<disable>0</disable>
|
||||||
|
<title>Contains Place</title>
|
||||||
|
<type>containsPlace</type>
|
||||||
|
<configuration><![CDATA[<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||||
|
<T3FlexForms>
|
||||||
|
<data>
|
||||||
|
<sheet index="sDEF">
|
||||||
|
<language index="lDEF">
|
||||||
|
<field index="storagePid">
|
||||||
|
<value index="vDEF">10</value>
|
||||||
|
</field>
|
||||||
|
<field index="containsPlaceId">
|
||||||
|
<value index="vDEF">043064193523-contains</value>
|
||||||
|
</field>
|
||||||
|
</language>
|
||||||
|
</sheet>
|
||||||
|
</data>
|
||||||
|
</T3FlexForms>]]></configuration>
|
||||||
|
</tx_thuecat_import_configuration>
|
||||||
|
</dataset>
|
|
@ -299,6 +299,50 @@ class ImportTest extends TestCase
|
||||||
$this->assertCSVDataSet('EXT:thuecat/Tests/Functional/Fixtures/Import/ImportsSyncScope.csv');
|
$this->assertCSVDataSet('EXT:thuecat/Tests/Functional/Fixtures/Import/ImportsSyncScope.csv');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function importsBasedOnContainsPlace(): void
|
||||||
|
{
|
||||||
|
$this->importDataSet(__DIR__ . '/Fixtures/Import/ImportsContainsPlace.xml');
|
||||||
|
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');
|
||||||
|
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/508431710173-wwne.json');
|
||||||
|
for ($i = 1; $i <= 4; $i++) {
|
||||||
|
GuzzleClientFaker::appendNotFoundResponse();
|
||||||
|
}
|
||||||
|
GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/396420044896-drzt.json');
|
||||||
|
for ($i = 1; $i <= 10; $i++) {
|
||||||
|
GuzzleClientFaker::appendNotFoundResponse();
|
||||||
|
}
|
||||||
|
GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/165868194223-zmqf.json');
|
||||||
|
GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/497839263245-edbm.json');
|
||||||
|
for ($i = 1; $i <= 2; $i++) {
|
||||||
|
GuzzleClientFaker::appendNotFoundResponse();
|
||||||
|
}
|
||||||
|
GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/e_23bec7f80c864c358da033dd75328f27-rfa.json');
|
||||||
|
for ($i = 1; $i <= 4; $i++) {
|
||||||
|
GuzzleClientFaker::appendNotFoundResponse();
|
||||||
|
}
|
||||||
|
GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/215230952334-yyno.json');
|
||||||
|
GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/052821473718-oxfq.json');
|
||||||
|
for ($i = 1; $i <= 4; $i++) {
|
||||||
|
GuzzleClientFaker::appendNotFoundResponse();
|
||||||
|
}
|
||||||
|
GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/440055527204-ocar.json');
|
||||||
|
for ($i = 1; $i <= 14; $i++) {
|
||||||
|
GuzzleClientFaker::appendNotFoundResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
$configuration = $this->get(ImportConfigurationRepository::class)->findByUid(1);
|
||||||
|
$this->get(Importer::class)->importConfiguration($configuration);
|
||||||
|
|
||||||
|
$this->assertCSVDataSet('EXT:thuecat/Tests/Functional/Fixtures/Import/ImportsContainsPlace.csv');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @test
|
* @test
|
||||||
* @testdox Referencing the same thing multiple times only adds it once.
|
* @testdox Referencing the same thing multiple times only adds it once.
|
||||||
|
|
|
@ -101,7 +101,10 @@ class SyncScopeUrlProviderTest extends TestCase
|
||||||
$configuration->_setProperty('syncScopeId', 10);
|
$configuration->_setProperty('syncScopeId', 10);
|
||||||
|
|
||||||
$fetchData = $this->createStub(FetchData::class);
|
$fetchData = $this->createStub(FetchData::class);
|
||||||
$fetchData->method('getResourceEndpoint')->willReturn('https://example.com/api/');
|
$fetchData->method('getFullResourceUrl')->willReturnOnConsecutiveCalls(
|
||||||
|
'https://example.com/api/835224016581-dara',
|
||||||
|
'https://example.com/api/165868194223-zmqf'
|
||||||
|
);
|
||||||
$fetchData->method('updatedNodes')->willReturn([
|
$fetchData->method('updatedNodes')->willReturn([
|
||||||
'data' => [
|
'data' => [
|
||||||
'createdOrUpdated' => [
|
'createdOrUpdated' => [
|
||||||
|
|
|
@ -326,11 +326,11 @@ parameters:
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Cannot call method findByUid\\(\\) on mixed\\.$#"
|
message: "#^Cannot call method findByUid\\(\\) on mixed\\.$#"
|
||||||
count: 10
|
count: 11
|
||||||
path: Tests/Functional/ImportTest.php
|
path: Tests/Functional/ImportTest.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Cannot call method importConfiguration\\(\\) on mixed\\.$#"
|
message: "#^Cannot call method importConfiguration\\(\\) on mixed\\.$#"
|
||||||
count: 10
|
count: 11
|
||||||
path: Tests/Functional/ImportTest.php
|
path: Tests/Functional/ImportTest.php
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue