From 61ae59c12740e555833e16d1561ec881f95280b9 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Thu, 15 Dec 2022 10:42:41 +0100 Subject: [PATCH] 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 --- Classes/Domain/Import/Importer.php | 26 ++- Classes/Domain/Import/Importer/FetchData.php | 7 +- .../UrlProvider/ContainsPlaceUrlProvider.php | 76 ++++++++ .../UrlProvider/SyncScopeUrlProvider.php | 7 +- .../Model/Backend/ImportConfiguration.php | 54 +++--- .../ImportConfiguration/ContainsPlace.xml | 36 ++++ .../TCA/tx_thuecat_import_configuration.php | 5 + Documentation/Changelog/1.3.0.rst | 4 + .../Private/Language/locallang_flexform.xlf | 14 ++ Resources/Private/Language/locallang_tca.xlf | 3 + .../resources/043064193523-contains.json | 182 ++++++++++++++++++ .../Fixtures/Import/ImportsContainsPlace.csv | 16 ++ .../Fixtures/Import/ImportsContainsPlace.xml | 64 ++++++ Tests/Functional/ImportTest.php | 44 +++++ .../UrlProvider/SyncScopeUrlProviderTest.php | 5 +- phpstan-baseline.neon | 4 +- 16 files changed, 515 insertions(+), 32 deletions(-) create mode 100644 Classes/Domain/Import/UrlProvider/ContainsPlaceUrlProvider.php create mode 100644 Configuration/FlexForm/ImportConfiguration/ContainsPlace.xml create mode 100644 Tests/Functional/Fixtures/Import/Guzzle/thuecat.org/resources/043064193523-contains.json create mode 100644 Tests/Functional/Fixtures/Import/ImportsContainsPlace.csv create mode 100644 Tests/Functional/Fixtures/Import/ImportsContainsPlace.xml diff --git a/Classes/Domain/Import/Importer.php b/Classes/Domain/Import/Importer.php index d252d3a..43acae6 100644 --- a/Classes/Domain/Import/Importer.php +++ b/Classes/Domain/Import/Importer.php @@ -23,6 +23,8 @@ declare(strict_types=1); 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\JsonDecode; use WerkraumMedia\ThueCat\Domain\Import\Entity\MapsToType; @@ -78,6 +80,11 @@ class Importer */ private $importLogRepository; + /** + * @var Logger + */ + private $logger; + /** * @var Import */ @@ -91,7 +98,8 @@ class Importer Languages $languages, ImportLogRepository $importLogRepository, FetchData $fetchData, - SaveData $saveData + SaveData $saveData, + LogManager $logManager ) { $this->urls = $urls; $this->converter = $converter; @@ -101,6 +109,7 @@ class Importer $this->importLogRepository = $importLogRepository; $this->fetchData = $fetchData; $this->saveData = $saveData; + $this->logger = $logManager->getLogger(__CLASS__); $this->import = new Import(); } @@ -111,6 +120,13 @@ class Importer $this->import->end(); 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()); } @@ -131,12 +147,15 @@ class Importer private function importResourceByUrl(string $url): void { + $this->logger->info('Process url.', ['url' => $url]); if ($this->import->handledRemoteId($url)) { + $this->logger->notice('Skip Url as we already handled it during import.', ['url' => $url]); return; } $content = $this->fetchData->jsonLDFromUrl($url); if ($content === []) { + $this->logger->notice('Skip Url as we did not receive any content.', ['url' => $url]); return; } @@ -153,12 +172,14 @@ class Importer $targetEntity = $this->entityRegistry->getEntityByTypes($jsonEntity['@type']); if ($targetEntity === '') { + $this->logger->notice('Skip entity, no target entity found.', ['types' => $jsonEntity['@type']]); return; } $entities = new EntityCollection(); foreach ($this->languages->getAvailable($this->import->getConfiguration()) as $language) { + $this->logger->info('Process entity for language.', ['language' => $language, 'targetEntity' => $targetEntity]); $mappedEntity = $this->entityMapper->mapDataToEntity( $jsonEntity, $targetEntity, @@ -167,6 +188,7 @@ class Importer ] ); if (!$mappedEntity instanceof MapsToType) { + $this->logger->alert('Mapping did not result in an MapsToType instance.', ['class' => get_class($mappedEntity)]); continue; } $convertedEntity = $this->converter->convert( @@ -176,6 +198,7 @@ class Importer ); if ($convertedEntity === null) { + $this->logger->alert('Could not convert entity.', ['language' => $language, 'targetEntity' => $targetEntity]); continue; } $entities->add($convertedEntity); @@ -199,6 +222,7 @@ class Importer } } + $this->logger->notice('Deny entity as type is not allowed.', ['types' => $jsonEntity['@type']]); return false; } } diff --git a/Classes/Domain/Import/Importer/FetchData.php b/Classes/Domain/Import/Importer/FetchData.php index e0851b8..5d5b2a0 100644 --- a/Classes/Domain/Import/Importer/FetchData.php +++ b/Classes/Domain/Import/Importer/FetchData.php @@ -76,6 +76,11 @@ class FetchData ); } + public function getFullResourceUrl(string $id): string + { + return $this->getResourceEndpoint() . ltrim($id, '/'); + } + public function jsonLDFromUrl(string $url): array { $cacheIdentifier = sha1($url); @@ -98,7 +103,7 @@ class FetchData return []; } - public function getResourceEndpoint(): string + private function getResourceEndpoint(): string { return $this->urlPrefix . '/resources/'; } diff --git a/Classes/Domain/Import/UrlProvider/ContainsPlaceUrlProvider.php b/Classes/Domain/Import/UrlProvider/ContainsPlaceUrlProvider.php new file mode 100644 index 0000000..8f0c752 --- /dev/null +++ b/Classes/Domain/Import/UrlProvider/ContainsPlaceUrlProvider.php @@ -0,0 +1,76 @@ + + * + * 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); + } +} diff --git a/Classes/Domain/Import/UrlProvider/SyncScopeUrlProvider.php b/Classes/Domain/Import/UrlProvider/SyncScopeUrlProvider.php index f2ff758..6afa5e4 100644 --- a/Classes/Domain/Import/UrlProvider/SyncScopeUrlProvider.php +++ b/Classes/Domain/Import/UrlProvider/SyncScopeUrlProvider.php @@ -65,13 +65,10 @@ class SyncScopeUrlProvider implements UrlProvider public function getUrls(): array { $response = $this->fetchData->updatedNodes($this->syncScopeId); - $resourceIds = array_values($response['data']['createdOrUpdated'] ?? []); - $urls = array_map(function (string $id) { - return $this->fetchData->getResourceEndpoint() . $id; + return array_map(function (string $id) { + return $this->fetchData->getFullResourceUrl($id); }, $resourceIds); - - return $urls; } } diff --git a/Classes/Domain/Model/Backend/ImportConfiguration.php b/Classes/Domain/Model/Backend/ImportConfiguration.php index 270cedc..046f898 100644 --- a/Classes/Domain/Model/Backend/ImportConfiguration.php +++ b/Classes/Domain/Model/Backend/ImportConfiguration.php @@ -106,14 +106,7 @@ class ImportConfiguration extends AbstractEntity implements ImportConfigurationI public function getStoragePid(): int { - if ($this->configuration === '') { - return 0; - } - - $storagePid = ArrayUtility::getValueByPath( - GeneralUtility::xml2array($this->configuration), - 'data/sDEF/lDEF/storagePid/vDEF' - ); + $storagePid = $this->getConfigurationValueFromFlexForm('storagePid'); if (is_numeric($storagePid) && $storagePid > 0) { return intval($storagePid); @@ -148,21 +141,16 @@ class ImportConfiguration extends AbstractEntity implements ImportConfigurationI public function getSyncScopeId(): string { - if ($this->configuration === '') { - return ''; + return $this->getConfigurationValueFromFlexForm('syncScopeId'); + } + + public function getContainsPlaceId(): string + { + $containsPlaceId = $this->getConfigurationValueFromFlexForm('containsPlaceId'); + if (!is_string($containsPlaceId)) { + throw new \Exception('Could not fetch containsPlaceId.', 1671027015); } - - $configurationAsArray = $this->getConfigurationAsArray(); - $arrayPath = 'data/sDEF/lDEF/syncScopeId/vDEF'; - - if (ArrayUtility::isValidPath($configurationAsArray, $arrayPath) === false) { - return ''; - } - - return ArrayUtility::getValueByPath( - $configurationAsArray, - $arrayPath - ); + return $containsPlaceId; } private function getEntries(): array @@ -198,4 +186,26 @@ class ImportConfiguration extends AbstractEntity implements ImportConfigurationI $configuration->allowedTypes = $allowedTypes; 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 + ); + } } diff --git a/Configuration/FlexForm/ImportConfiguration/ContainsPlace.xml b/Configuration/FlexForm/ImportConfiguration/ContainsPlace.xml new file mode 100644 index 0000000..0218b0e --- /dev/null +++ b/Configuration/FlexForm/ImportConfiguration/ContainsPlace.xml @@ -0,0 +1,36 @@ + + + 1 + + + + + + LLL:EXT:thuecat/Resources/Private/Language/locallang_flexform.xlf:importConfiguration.containsPlace.sheetTitle + + array + + + + + + input + int,required + + + + + + + LLL:EXT:thuecat/Resources/Private/Language/locallang_flexform.xlf:importConfiguration.containsPlace.containsPlaceId.description + + input + trim,required + + + + + + + + diff --git a/Configuration/TCA/tx_thuecat_import_configuration.php b/Configuration/TCA/tx_thuecat_import_configuration.php index 3867b78..1ef5ccd 100644 --- a/Configuration/TCA/tx_thuecat_import_configuration.php +++ b/Configuration/TCA/tx_thuecat_import_configuration.php @@ -45,6 +45,10 @@ return (static function (string $extensionKey, string $tableName) { $languagePath . '.type.syncScope', 'syncScope', ], + [ + $languagePath . '.type.containsPlace', + 'containsPlace', + ], ], ], ], @@ -57,6 +61,7 @@ return (static function (string $extensionKey, string $tableName) { 'default' => $flexFormConfigurationPath . 'ImportConfiguration/Static.xml', 'static' => $flexFormConfigurationPath . 'ImportConfiguration/Static.xml', 'syncScope' => $flexFormConfigurationPath . 'ImportConfiguration/SyncScope.xml', + 'containsPlace' => $flexFormConfigurationPath . 'ImportConfiguration/ContainsPlace.xml', ], ], ], diff --git a/Documentation/Changelog/1.3.0.rst b/Documentation/Changelog/1.3.0.rst index 518a11e..603a8d0 100644 --- a/Documentation/Changelog/1.3.0.rst +++ b/Documentation/Changelog/1.3.0.rst @@ -13,6 +13,10 @@ Features * 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. * Filter and sort opening hours. diff --git a/Resources/Private/Language/locallang_flexform.xlf b/Resources/Private/Language/locallang_flexform.xlf index 84bc748..f852cc8 100644 --- a/Resources/Private/Language/locallang_flexform.xlf +++ b/Resources/Private/Language/locallang_flexform.xlf @@ -28,6 +28,20 @@ syncScopeId + + + Contains place import configuration + + + Storage Page UID + + + Contains Place ID + + + Only ID, not full URL e.g. 043064193523-jcyt + + Tourist Attraction diff --git a/Resources/Private/Language/locallang_tca.xlf b/Resources/Private/Language/locallang_tca.xlf index ff409e0..c5d5c49 100644 --- a/Resources/Private/Language/locallang_tca.xlf +++ b/Resources/Private/Language/locallang_tca.xlf @@ -242,6 +242,9 @@ Synchronization area + + Contains Place + Configuration diff --git a/Tests/Functional/Fixtures/Import/Guzzle/thuecat.org/resources/043064193523-contains.json b/Tests/Functional/Fixtures/Import/Guzzle/thuecat.org/resources/043064193523-contains.json new file mode 100644 index 0000000..5029cfa --- /dev/null +++ b/Tests/Functional/Fixtures/Import/Guzzle/thuecat.org/resources/043064193523-contains.json @@ -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" + } + ] + } + ] +} diff --git a/Tests/Functional/Fixtures/Import/ImportsContainsPlace.csv b/Tests/Functional/Fixtures/Import/ImportsContainsPlace.csv new file mode 100644 index 0000000..4d34c99 --- /dev/null +++ b/Tests/Functional/Fixtures/Import/ImportsContainsPlace.csv @@ -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", diff --git a/Tests/Functional/Fixtures/Import/ImportsContainsPlace.xml b/Tests/Functional/Fixtures/Import/ImportsContainsPlace.xml new file mode 100644 index 0000000..e756748 --- /dev/null +++ b/Tests/Functional/Fixtures/Import/ImportsContainsPlace.xml @@ -0,0 +1,64 @@ + + + + 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/ImportTest.php b/Tests/Functional/ImportTest.php index cd1be3b..dd9f239 100644 --- a/Tests/Functional/ImportTest.php +++ b/Tests/Functional/ImportTest.php @@ -299,6 +299,50 @@ class ImportTest extends TestCase $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 * @testdox Referencing the same thing multiple times only adds it once. diff --git a/Tests/Unit/Domain/Import/UrlProvider/SyncScopeUrlProviderTest.php b/Tests/Unit/Domain/Import/UrlProvider/SyncScopeUrlProviderTest.php index df7a280..563345f 100644 --- a/Tests/Unit/Domain/Import/UrlProvider/SyncScopeUrlProviderTest.php +++ b/Tests/Unit/Domain/Import/UrlProvider/SyncScopeUrlProviderTest.php @@ -101,7 +101,10 @@ class SyncScopeUrlProviderTest extends TestCase $configuration->_setProperty('syncScopeId', 10); $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([ 'data' => [ 'createdOrUpdated' => [ diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 27acf73..89d4597 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -326,11 +326,11 @@ parameters: - message: "#^Cannot call method findByUid\\(\\) on mixed\\.$#" - count: 10 + count: 11 path: Tests/Functional/ImportTest.php - message: "#^Cannot call method importConfiguration\\(\\) on mixed\\.$#" - count: 10 + count: 11 path: Tests/Functional/ImportTest.php