From 64785260049fde2920ca6e823a26262a46f6ec44 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Tue, 16 Feb 2021 15:08:15 +0100 Subject: [PATCH] Add media to tourist attraction --- .../Import/Converter/TouristAttraction.php | 1 + Classes/Domain/Import/Importer/FetchData.php | 19 +- Classes/Domain/Import/JsonLD/Parser.php | 12 +- .../Domain/Import/JsonLD/Parser/Address.php | 13 +- Classes/Domain/Import/JsonLD/Parser/Media.php | 93 +++++++ Classes/Domain/Import/RequestFactory.php | 2 +- Classes/Domain/Model/Frontend/Address.php | 10 + Classes/Domain/Model/Frontend/Media.php | 64 +++++ .../Model/Frontend/TouristAttraction.php | 6 + Classes/Extension.php | 18 ++ Configuration/Services.yaml | 9 + .../TCA/tx_thuecat_tourist_attraction.php | 9 +- .../ContentElement/TouristAttraction.html | 4 + .../Converter/TouristAttractionTest.php | 4 + .../Domain/Import/Importer/FetchDataTest.php | 46 +++- .../Import/JsonLD/Parser/AddressTest.php | 134 +++++++++- .../Domain/Import/JsonLD/Parser/MediaTest.php | 251 ++++++++++++++++++ .../Unit/Domain/Import/JsonLD/ParserTest.php | 101 ++++++- .../Unit/Domain/Import/RequestFactoryTest.php | 2 +- .../Domain/Model/Frontend/AddressTest.php | 22 +- .../Unit/Domain/Model/Frontend/MediaTest.php | 86 ++++++ ext_tables.sql | 1 + 22 files changed, 877 insertions(+), 30 deletions(-) create mode 100644 Classes/Domain/Import/JsonLD/Parser/Media.php create mode 100644 Classes/Domain/Model/Frontend/Media.php create mode 100644 Tests/Unit/Domain/Import/JsonLD/Parser/MediaTest.php create mode 100644 Tests/Unit/Domain/Model/Frontend/MediaTest.php diff --git a/Classes/Domain/Import/Converter/TouristAttraction.php b/Classes/Domain/Import/Converter/TouristAttraction.php index 8302652..ffbc121 100644 --- a/Classes/Domain/Import/Converter/TouristAttraction.php +++ b/Classes/Domain/Import/Converter/TouristAttraction.php @@ -72,6 +72,7 @@ class TouristAttraction implements Converter 'town' => $town ? $town->getUid() : 0, 'opening_hours' => json_encode($this->parser->getOpeningHours($jsonLD)), 'address' => json_encode($this->parser->getAddress($jsonLD)), + 'media' => json_encode($this->parser->getMedia($jsonLD)), ] ); $entities->add($entity); diff --git a/Classes/Domain/Import/Importer/FetchData.php b/Classes/Domain/Import/Importer/FetchData.php index 7f7fcd8..637fe71 100644 --- a/Classes/Domain/Import/Importer/FetchData.php +++ b/Classes/Domain/Import/Importer/FetchData.php @@ -25,28 +25,39 @@ namespace WerkraumMedia\ThueCat\Domain\Import\Importer; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestFactoryInterface; +use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface as CacheFrontendInterface; class FetchData { private RequestFactoryInterface $requestFactory; private ClientInterface $httpClient; + private CacheFrontendInterface $cache; public function __construct( RequestFactoryInterface $requestFactory, - ClientInterface $httpClient + ClientInterface $httpClient, + CacheFrontendInterface $cache ) { $this->requestFactory = $requestFactory; $this->httpClient = $httpClient; + $this->cache = $cache; } public function jsonLDFromUrl(string $url): array { + $cacheIdentifier = sha1($url); + $cacheEntry = $this->cache->get($cacheIdentifier); + if (is_array($cacheEntry)) { + return $cacheEntry; + } + $request = $this->requestFactory->createRequest('GET', $url); $response = $this->httpClient->sendRequest($request); - $json = json_decode((string) $response->getBody(), true); - if (is_array($json)) { - return $json; + $jsonLD = json_decode((string) $response->getBody(), true); + if (is_array($jsonLD)) { + $this->cache->set($cacheIdentifier, $jsonLD); + return $jsonLD; } return []; diff --git a/Classes/Domain/Import/JsonLD/Parser.php b/Classes/Domain/Import/JsonLD/Parser.php index 2d50b0e..c3cb46b 100644 --- a/Classes/Domain/Import/JsonLD/Parser.php +++ b/Classes/Domain/Import/JsonLD/Parser.php @@ -24,20 +24,25 @@ namespace WerkraumMedia\ThueCat\Domain\Import\JsonLD; */ use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Address; +use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Media; use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\OpeningHours; class Parser { private OpeningHours $openingHours; private Address $address; + private Media $media; public function __construct( OpeningHours $openingHours, - Address $address + Address $address, + Media $media ) { $this->openingHours = $openingHours; $this->address = $address; + $this->media = $media; } + public function getId(array $jsonLD): string { return $jsonLD['@id']; @@ -78,6 +83,11 @@ class Parser return $this->address->get($jsonLD); } + public function getMedia(array $jsonLD): array + { + return $this->media->get($jsonLD); + } + /** * @return string[] */ diff --git a/Classes/Domain/Import/JsonLD/Parser/Address.php b/Classes/Domain/Import/JsonLD/Parser/Address.php index 3d9b70a..b203060 100644 --- a/Classes/Domain/Import/JsonLD/Parser/Address.php +++ b/Classes/Domain/Import/JsonLD/Parser/Address.php @@ -26,9 +26,7 @@ class Address public function get(array $jsonLD): array { $address = $jsonLD['schema:address'] ?? []; - if (isset($address['@id']) === false) { - return []; - } + $geo = $jsonLD['schema:geo'] ?? []; return [ 'street' => $this->getStreet($address), @@ -37,6 +35,7 @@ class Address 'email' => $this->getEmail($address), 'phone' => $this->getPhone($address), 'fax' => $this->getFax($address), + 'geo' => $this->getGeo($geo), ]; } @@ -69,4 +68,12 @@ class Address { return $address['schema:faxNumber']['@value'] ?? ''; } + + private function getGeo(array $geo): array + { + return [ + 'latitude' => floatval($geo['schema:latitude']['@value'] ?? 0.00), + 'longitude' => floatval($geo['schema:longitude']['@value'] ?? 0.00), + ]; + } } diff --git a/Classes/Domain/Import/JsonLD/Parser/Media.php b/Classes/Domain/Import/JsonLD/Parser/Media.php new file mode 100644 index 0000000..9b4a7e5 --- /dev/null +++ b/Classes/Domain/Import/JsonLD/Parser/Media.php @@ -0,0 +1,93 @@ + + * + * 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\FetchData; + +class Media +{ + private FetchData $fetchData; + + public function __construct( + FetchData $fetchData + ) { + $this->fetchData = $fetchData; + } + + public function get(array $jsonLD): array + { + $media = []; + + if (isset($jsonLD['schema:photo']['@id'])) { + $media[] = array_merge( + [ + 'mainImage' => true, + ], + $this->getMedia($jsonLD['schema:photo']['@id']) + ); + } + + if (isset($jsonLD['schema:image']['@id'])) { + $media[] = array_merge( + [ + 'mainImage' => false, + ], + $this->getMedia($jsonLD['schema:image']['@id']) + ); + } + + if ( + isset($jsonLD['schema:image']) + && isset($jsonLD['schema:image']['@id']) === false + && is_array($jsonLD['schema:image']) + ) { + foreach ($jsonLD['schema:image'] as $image) { + $media[] = array_merge( + [ + 'mainImage' => false, + ], + $this->getMedia($image['@id']) + ); + } + } + + return $media; + } + + private function getMedia(string $resourceId): array + { + $jsonLD = $this->fetchData->jsonLDFromUrl($resourceId); + $resource = $jsonLD['@graph'][0] ?? []; + + return [ + 'type' => 'image', + 'title' => $resource['schema:name']['@value'] ?? '', + 'description' => $resource['schema:description']['@value'] ?? '', + 'url' => $resource['schema:url']['@value'] ?? '', + 'copyrightYear' => intval($resource['schema:copyrightYear']['@value'] ?? 0), + 'license' => [ + 'type' => $resource['schema:license']['@value'] ?? '', + 'author' => $resource['thuecat:licenseAuthor']['@value'] ?? '', + ], + ]; + } +} diff --git a/Classes/Domain/Import/RequestFactory.php b/Classes/Domain/Import/RequestFactory.php index 2080442..a2773f0 100644 --- a/Classes/Domain/Import/RequestFactory.php +++ b/Classes/Domain/Import/RequestFactory.php @@ -32,7 +32,7 @@ class RequestFactory extends Typo3RequestFactory public function createRequest(string $method, $uri): RequestInterface { $uri = new Uri((string) $uri); - $uri = $uri->withQuery('?format=jsonId'); + $uri = $uri->withQuery('?format=jsonld'); // TODO: Add api key from site diff --git a/Classes/Domain/Model/Frontend/Address.php b/Classes/Domain/Model/Frontend/Address.php index 5c73811..f1ecdfc 100644 --- a/Classes/Domain/Model/Frontend/Address.php +++ b/Classes/Domain/Model/Frontend/Address.php @@ -66,6 +66,16 @@ class Address implements TypeInterface return $this->data['fax'] ?? ''; } + public function getLatitute(): float + { + return $this->data['geo']['latitude'] ?? 0.0; + } + + public function getLongitude(): float + { + return $this->data['geo']['longitude'] ?? 0.0; + } + public function __toString(): string { return $this->serialized; diff --git a/Classes/Domain/Model/Frontend/Media.php b/Classes/Domain/Model/Frontend/Media.php new file mode 100644 index 0000000..d8be397 --- /dev/null +++ b/Classes/Domain/Model/Frontend/Media.php @@ -0,0 +1,64 @@ + + * + * 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\Type\TypeInterface; + +class Media implements TypeInterface +{ + private string $serialized; + private array $data; + + public function __construct(string $serialized) + { + $this->serialized = $serialized; + $this->data = json_decode($serialized, true); + } + + public function getMainImage(): array + { + foreach ($this->data as $media) { + if ( + $media['type'] === 'image' + && $media['mainImage'] === true + ) { + return $media; + } + } + + return []; + } + + public function getImages(): array + { + return array_filter($this->data, function (array $media) { + return $media['type'] === 'image'; + }); + } + + public function __toString(): string + { + return $this->serialized; + } +} diff --git a/Classes/Domain/Model/Frontend/TouristAttraction.php b/Classes/Domain/Model/Frontend/TouristAttraction.php index e29f1d3..9207cb9 100644 --- a/Classes/Domain/Model/Frontend/TouristAttraction.php +++ b/Classes/Domain/Model/Frontend/TouristAttraction.php @@ -32,6 +32,7 @@ class TouristAttraction extends AbstractEntity protected ?OpeningHours $openingHours = null; protected ?Address $address = null; protected ?Town $town = null; + protected ?Media $media = null; public function getTitle(): string { @@ -57,4 +58,9 @@ class TouristAttraction extends AbstractEntity { return $this->town; } + + public function getMedia(): ?Media + { + return $this->media; + } } diff --git a/Classes/Extension.php b/Classes/Extension.php index 293a135..1845db5 100644 --- a/Classes/Extension.php +++ b/Classes/Extension.php @@ -23,6 +23,7 @@ namespace WerkraumMedia\ThueCat; * 02110-1301, USA. */ +use TYPO3\CMS\Core\Cache\Backend\TransientMemoryBackend; use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; use TYPO3\CMS\Extbase\Utility\ExtensionUtility; use WerkraumMedia\ThueCat\Controller\Backend\ImportController; @@ -61,6 +62,12 @@ class Extension } public static function registerConfig(): void + { + self::addCaching(); + self::addContentElements(); + } + + private static function addContentElements(): void { $languagePath = self::getLanguagePath() . 'locallang_tca.xlf:tt_content'; @@ -81,4 +88,15 @@ class Extension } '); } + + private static function addCaching(): void + { + $cacheIdentifier = 'thuecat_fetchdata'; + if (!is_array($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'][$cacheIdentifier])) { + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'][$cacheIdentifier] = []; + } + if (!isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'][$cacheIdentifier]['backend'])) { + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'][$cacheIdentifier]['backend'] = TransientMemoryBackend::class; + } + } } diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index 0f313d9..66412d7 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -10,7 +10,16 @@ services: WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData: arguments: $requestFactory: '@WerkraumMedia\ThueCat\Domain\Import\RequestFactory' + $cache: '@cache.thuecat_fetchdata' WerkraumMedia\ThueCat\Frontend\DataProcessing\: resource: '../Classes/Frontend/DataProcessing/*' public: true + + 'cache.thuecat_fetchdata': + class: 'TYPO3\CMS\Core\Cache\Frontend\FrontendInterface' + factory: + - '@TYPO3\CMS\Core\Cache\CacheManager' + - 'getCache' + arguments: + - 'thuecat_fetchdata' diff --git a/Configuration/TCA/tx_thuecat_tourist_attraction.php b/Configuration/TCA/tx_thuecat_tourist_attraction.php index 534a536..f4ee0a2 100644 --- a/Configuration/TCA/tx_thuecat_tourist_attraction.php +++ b/Configuration/TCA/tx_thuecat_tourist_attraction.php @@ -49,6 +49,13 @@ return (static function (string $extensionKey, string $tableName) { 'readOnly' => true, ], ], + 'media' => [ + 'label' => $languagePath . '.media', + 'config' => [ + 'type' => 'text', + 'readOnly' => true, + ], + ], 'remote_id' => [ 'label' => $languagePath . '.remote_id', 'config' => [ @@ -89,7 +96,7 @@ return (static function (string $extensionKey, string $tableName) { ], 'types' => [ '0' => [ - 'showitem' => 'title, description, opening_hours, address, remote_id, town, managed_by', + 'showitem' => 'title, description, opening_hours, address, media, remote_id, town, managed_by', ], ], ]; diff --git a/Resources/Private/Templates/Frontend/ContentElement/TouristAttraction.html b/Resources/Private/Templates/Frontend/ContentElement/TouristAttraction.html index 043d89f..87ce4f1 100644 --- a/Resources/Private/Templates/Frontend/ContentElement/TouristAttraction.html +++ b/Resources/Private/Templates/Frontend/ContentElement/TouristAttraction.html @@ -4,6 +4,10 @@
{entity.title} ({entity.town.title})

{entity.description}

+ + + +

diff --git a/Tests/Unit/Domain/Import/Converter/TouristAttractionTest.php b/Tests/Unit/Domain/Import/Converter/TouristAttractionTest.php index 0017cd6..7f7db10 100644 --- a/Tests/Unit/Domain/Import/Converter/TouristAttractionTest.php +++ b/Tests/Unit/Domain/Import/Converter/TouristAttractionTest.php @@ -118,6 +118,7 @@ class TouristAttractionTest extends TestCase $parser->getDescription($jsonLD, 'de')->willReturn('Description'); $parser->getOpeningHours($jsonLD)->willReturn([]); $parser->getAddress($jsonLD)->willReturn([]); + $parser->getMedia($jsonLD)->willReturn([]); $organisationRepository = $this->prophesize(OrganisationRepository::class); $townRepository = $this->prophesize(TownRepository::class); @@ -144,6 +145,7 @@ class TouristAttractionTest extends TestCase 'town' => 0, 'opening_hours' => '[]', 'address' => '[]', + 'media' => '[]', ], $entity->getData()); } @@ -187,6 +189,7 @@ class TouristAttractionTest extends TestCase $parser->getDescription($jsonLD, 'de')->willReturn('Description'); $parser->getOpeningHours($jsonLD)->willReturn([]); $parser->getAddress($jsonLD)->willReturn([]); + $parser->getMedia($jsonLD)->willReturn([]); $organisation = $this->prophesize(Organisation::class); $organisation->getUid()->willReturn(10); @@ -223,6 +226,7 @@ class TouristAttractionTest extends TestCase 'town' => 20, 'opening_hours' => '[]', 'address' => '[]', + 'media' => '[]', ], $entity->getData()); } } diff --git a/Tests/Unit/Domain/Import/Importer/FetchDataTest.php b/Tests/Unit/Domain/Import/Importer/FetchDataTest.php index a6698bd..a9ffd82 100644 --- a/Tests/Unit/Domain/Import/Importer/FetchDataTest.php +++ b/Tests/Unit/Domain/Import/Importer/FetchDataTest.php @@ -29,6 +29,7 @@ use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestFactoryInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; +use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface; use WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData; /** @@ -45,10 +46,12 @@ class FetchDataTest extends TestCase { $requestFactory = $this->prophesize(RequestFactoryInterface::class); $httpClient = $this->prophesize(ClientInterface::class); + $cache = $this->prophesize(FrontendInterface::class); $subject = new FetchData( $requestFactory->reveal(), - $httpClient->reveal() + $httpClient->reveal(), + $cache->reveal() ); self::assertInstanceOf(FetchData::class, $subject); @@ -61,6 +64,7 @@ class FetchDataTest extends TestCase { $requestFactory = $this->prophesize(RequestFactoryInterface::class); $httpClient = $this->prophesize(ClientInterface::class); + $cache = $this->prophesize(FrontendInterface::class); $request = $this->prophesize(RequestInterface::class); $response = $this->prophesize(ResponseInterface::class); @@ -75,7 +79,8 @@ class FetchDataTest extends TestCase $subject = new FetchData( $requestFactory->reveal(), - $httpClient->reveal() + $httpClient->reveal(), + $cache->reveal() ); $result = $subject->jsonLDFromUrl('https://example.com/resources/018132452787-ngbe'); @@ -95,6 +100,7 @@ class FetchDataTest extends TestCase { $requestFactory = $this->prophesize(RequestFactoryInterface::class); $httpClient = $this->prophesize(ClientInterface::class); + $cache = $this->prophesize(FrontendInterface::class); $request = $this->prophesize(RequestInterface::class); $response = $this->prophesize(ResponseInterface::class); @@ -109,10 +115,44 @@ class FetchDataTest extends TestCase $subject = new FetchData( $requestFactory->reveal(), - $httpClient->reveal() + $httpClient->reveal(), + $cache->reveal() ); $result = $subject->jsonLDFromUrl('https://example.com/resources/018132452787-ngbe'); self::assertSame([], $result); } + + /** + * @test + */ + public function returnsResultFromCacheIfAvailable(): void + { + $requestFactory = $this->prophesize(RequestFactoryInterface::class); + $httpClient = $this->prophesize(ClientInterface::class); + $cache = $this->prophesize(FrontendInterface::class); + + $cache->get('03c8a7eb2a06e47c28883d95f7e834089baf9c3e')->willReturn([ + '@graph' => [ + [ + '@id' => 'https://example.com/resources/018132452787-ngbe', + ], + ], + ]); + + $subject = new FetchData( + $requestFactory->reveal(), + $httpClient->reveal(), + $cache->reveal() + ); + + $result = $subject->jsonLDFromUrl('https://example.com/resources/018132452787-ngbe'); + self::assertSame([ + '@graph' => [ + [ + '@id' => 'https://example.com/resources/018132452787-ngbe', + ], + ], + ], $result); + } } diff --git a/Tests/Unit/Domain/Import/JsonLD/Parser/AddressTest.php b/Tests/Unit/Domain/Import/JsonLD/Parser/AddressTest.php index 09672ad..89577b3 100644 --- a/Tests/Unit/Domain/Import/JsonLD/Parser/AddressTest.php +++ b/Tests/Unit/Domain/Import/JsonLD/Parser/AddressTest.php @@ -21,8 +21,8 @@ namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import\JsonLD\Parser; * 02110-1301, USA. */ -use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Address; use PHPUnit\Framework\TestCase; +use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Address; /** * @covers WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Address @@ -43,14 +43,125 @@ class AddressTest extends TestCase /** * @test */ - public function returnsEmptyArrayAsFallback(): void + public function returnsFallback(): void { $subject = new Address( ); $result = $subject->get([]); - self::assertSame([], $result); + self::assertSame([ + 'street' => '', + 'zip' => '', + 'city' => '', + 'email' => '', + 'phone' => '', + 'fax' => '', + 'geo' => [ + 'latitude' => 0.0, + 'longitude' => 0.0, + ], + ], $result); + } + + /** + * @test + */ + public function returnsAddress(): void + { + $subject = new Address( + ); + + $result = $subject->get([ + 'schema:address' => [ + '@id' => 'genid-28b33237f71b41e3ad54a99e1da769b9-b0', + 'schema:addressLocality' => [ + '@language' => 'de', + '@value' => 'Erfurt', + ], + 'schema:addressCountry' => [ + '@type' => 'thuecat:AddressCountry', + '@value' => 'thuecat:Germany', + ], + 'schema:postalCode' => [ + '@language' => 'de', + '@value' => '99084', + ], + 'schema:addressRegion' => [ + '@type' => 'thuecat:AddressFederalState', + '@value' => 'thuecat:Thuringia', + ], + 'schema:telephone' => [ + '@language' => 'de', + '@value' => '+49 361 999999', + ], + 'schema:email' => [ + '@language' => 'de', + '@value' => 'altesynagoge@example.com', + ], + 'schema:streetAddress' => [ + '@language' => 'de', + '@value' => 'Waagegasse 8', + ], + 'schema:faxNumber' => [ + '@language' => 'de', + '@value' => '+49 361 999998', + ], + 'thuecat:typOfAddress' => [ + '@type' => 'thuecat:TypOfAddress', + '@value' => 'thuecat:HouseAddress', + ], + ], + ]); + + self::assertSame([ + 'street' => 'Waagegasse 8', + 'zip' => '99084', + 'city' => 'Erfurt', + 'email' => 'altesynagoge@example.com', + 'phone' => '+49 361 999999', + 'fax' => '+49 361 999998', + 'geo' => [ + 'latitude' => 0.0, + 'longitude' => 0.0, + ], + ], $result); + } + + /** + * @test + */ + public function returnsGeo(): void + { + $subject = new Address( + ); + + $result = $subject->get([ + 'schema:geo' => [ + '@id' => 'genid-28b33237f71b41e3ad54a99e1da769b9-b4', + 'schema:longitude' => [ + '@type' => 'schema:Number', + '@value' => '11.029133', + ], + 'schema:latitude' => [ + '@type' => 'schema:Number', + '@value' => '50.978765', + ], + ], + ]); + + self::assertSame([ + 'street' => '', + 'zip' => '', + 'city' => '', + 'email' => '', + 'phone' => '', + 'fax' => '', + 'geo' => [ + 'latitude' => 50.978765, + 'longitude' => 11.029133, + ], + ], $result); } /** @@ -99,7 +210,18 @@ class AddressTest extends TestCase 'thuecat:typOfAddress' => [ '@type' => 'thuecat:TypOfAddress', '@value' => 'thuecat:HouseAddress', - ] + ], + ], + 'schema:geo' => [ + '@id' => 'genid-28b33237f71b41e3ad54a99e1da769b9-b4', + 'schema:longitude' => [ + '@type' => 'schema:Number', + '@value' => '11.029133', + ], + 'schema:latitude' => [ + '@type' => 'schema:Number', + '@value' => '50.978765', + ], ], ]); @@ -110,6 +232,10 @@ class AddressTest extends TestCase 'email' => 'altesynagoge@example.com', 'phone' => '+49 361 999999', 'fax' => '+49 361 999998', + 'geo' => [ + 'latitude' => 50.978765, + 'longitude' => 11.029133, + ], ], $result); } } diff --git a/Tests/Unit/Domain/Import/JsonLD/Parser/MediaTest.php b/Tests/Unit/Domain/Import/JsonLD/Parser/MediaTest.php new file mode 100644 index 0000000..da8f285 --- /dev/null +++ b/Tests/Unit/Domain/Import/JsonLD/Parser/MediaTest.php @@ -0,0 +1,251 @@ + + * + * 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 PHPUnit\Framework\TestCase; +use Prophecy\PhpUnit\ProphecyTrait; +use WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData; +use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Media; + +/** + * @covers WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Media + */ +class MediaTest extends TestCase +{ + use ProphecyTrait; + + /** + * @test + */ + public function canBeCreated(): void + { + $fetchData = $this->prophesize(FetchData::class); + + $subject = new Media( + $fetchData->reveal() + ); + + self::assertInstanceOf(Media::class, $subject); + } + + /** + * @test + */ + public function returnsFallback(): void + { + $fetchData = $this->prophesize(FetchData::class); + + $subject = new Media( + $fetchData->reveal() + ); + + $result = $subject->get([]); + + self::assertSame([], $result); + } + + /** + * @test + */ + public function returnsPhotoAndImage(): void + { + $fetchData = $this->prophesize(FetchData::class); + + $fetchData->jsonLDFromUrl('https://thuecat.org/resources/dms_5099196')->willReturn([ + '@graph' => [ + 0 => [ + 'schema:name' => [ + '@language' => 'de', + '@value' => 'Erfurt-Alte Synagoge', + ], + 'schema:description' => [ + '@language' => 'de', + '@value' => 'Frontaler Blick auf die Hausfront/Hausfassade im Innenhof mit Zugang über die Waagegasse', + ], + 'schema:copyrightYear' => [ + '@language' => 'de', + '@value' => '2009', + ], + 'schema:url' => [ + '@type' => 'xsd:anyURI', + '@value' => 'https://cms.thuecat.org/o/adaptive-media/image/5099196/Preview-1280x0/image', + ], + 'schema:license' => [ + '@language' => 'de', + '@value' => 'https://creativecommons.org/licenses/by/4.0/', + ], + 'thuecat:licenseAuthor' => [ + '@language' => 'de', + '@value' => 'F:\Bilddatenbank\Museen und Ausstellungen\Alte Synagoge', + ], + ], + ], + ]); + + $subject = new Media( + $fetchData->reveal() + ); + + $result = $subject->get([ + 'schema:photo' => [ + '@id' => 'https://thuecat.org/resources/dms_5099196', + ], + 'schema:image' => [ + '@id' => 'https://thuecat.org/resources/dms_5099196', + ], + ]); + + self::assertSame([ + [ + 'mainImage' => true, + 'type' => 'image', + 'title' => 'Erfurt-Alte Synagoge', + 'description' => 'Frontaler Blick auf die Hausfront/Hausfassade im Innenhof mit Zugang über die Waagegasse', + 'url' => 'https://cms.thuecat.org/o/adaptive-media/image/5099196/Preview-1280x0/image', + 'copyrightYear' => 2009, + 'license' => [ + 'type' => 'https://creativecommons.org/licenses/by/4.0/', + 'author' => 'F:\Bilddatenbank\Museen und Ausstellungen\Alte Synagoge', + ], + ], + [ + 'mainImage' => false, + 'type' => 'image', + 'title' => 'Erfurt-Alte Synagoge', + 'description' => 'Frontaler Blick auf die Hausfront/Hausfassade im Innenhof mit Zugang über die Waagegasse', + 'url' => 'https://cms.thuecat.org/o/adaptive-media/image/5099196/Preview-1280x0/image', + 'copyrightYear' => 2009, + 'license' => [ + 'type' => 'https://creativecommons.org/licenses/by/4.0/', + 'author' => 'F:\Bilddatenbank\Museen und Ausstellungen\Alte Synagoge', + ], + ], + ], $result); + } + + /** + * @test + */ + public function returnsMultipleImages(): void + { + $fetchData = $this->prophesize(FetchData::class); + + $fetchData->jsonLDFromUrl('https://thuecat.org/resources/dms_5159186')->willReturn([ + '@graph' => [ + 0 => [ + 'schema:description' => [ + '@language' => 'de', + '@value' => 'Sicht auf Dom St. Marien, St. Severikirche sowie die davor liegenden Klostergebäude und einem Ausschnitt des Biergartens umgeben von einem dämmerungsverfärten Himmel', + ], + 'schema:name' => [ + '@language' => 'de', + '@value' => 'Erfurt-Dom-und-Severikirche.jpg', + ], + 'schema:url' => [ + '@type' => 'xsd:anyURI', + '@value' => 'https://cms.thuecat.org/o/adaptive-media/image/5159186/Preview-1280x0/image', + ], + 'schema:copyrightYear' => [ + '@language' => 'de', + '@value' => '2020', + ], + 'schema:license' => [ + '@language' => 'de', + '@value' => 'https://creativecommons.org/licenses/by/4.0/', + ], + 'thuecat:licenseAuthor' => [ + '@language' => 'de', + '@value' => '', + ], + ], + ], + ]); + $fetchData->jsonLDFromUrl('https://thuecat.org/resources/dms_5159216')->willReturn([ + '@graph' => [ + 0 => [ + 'schema:name' => [ + '@language' => 'de', + '@value' => 'Erfurt-Dom und Severikirche-beleuchtet.jpg', + ], + 'schema:copyrightYear' => [ + '@language' => 'de', + '@value' => '2016', + ], + 'schema:url' => [ + '@type' => 'xsd:anyURI', + '@value' => 'https://cms.thuecat.org/o/adaptive-media/image/5159216/Preview-1280x0/image', + ], + 'schema:license' => [ + '@language' => 'de', + '@value' => 'https://creativecommons.org/licenses/by/4.0/', + ], + 'thuecat:licenseAuthor' => [ + '@language' => 'de', + '@value' => '', + ], + ], + ], + ]); + + $subject = new Media( + $fetchData->reveal() + ); + + $result = $subject->get([ + 'schema:image' => [ + 0 => [ + '@id' => 'https://thuecat.org/resources/dms_5159186', + ], + 1 => [ + '@id' => 'https://thuecat.org/resources/dms_5159216', + ], + ], + ]); + + self::assertSame([ + [ + 'mainImage' => false, + 'type' => 'image', + 'title' => 'Erfurt-Dom-und-Severikirche.jpg', + 'description' => 'Sicht auf Dom St. Marien, St. Severikirche sowie die davor liegenden Klostergebäude und einem Ausschnitt des Biergartens umgeben von einem dämmerungsverfärten Himmel', + 'url' => 'https://cms.thuecat.org/o/adaptive-media/image/5159186/Preview-1280x0/image', + 'copyrightYear' => 2020, + 'license' => [ + 'type' => 'https://creativecommons.org/licenses/by/4.0/', + 'author' => '', + ], + ], + [ + 'mainImage' => false, + 'type' => 'image', + 'title' => 'Erfurt-Dom und Severikirche-beleuchtet.jpg', + 'description' => '', + 'url' => 'https://cms.thuecat.org/o/adaptive-media/image/5159216/Preview-1280x0/image', + 'copyrightYear' => 2016, + 'license' => [ + 'type' => 'https://creativecommons.org/licenses/by/4.0/', + 'author' => '', + ], + ], + ], $result); + } +} diff --git a/Tests/Unit/Domain/Import/JsonLD/ParserTest.php b/Tests/Unit/Domain/Import/JsonLD/ParserTest.php index efb1288..5d48316 100644 --- a/Tests/Unit/Domain/Import/JsonLD/ParserTest.php +++ b/Tests/Unit/Domain/Import/JsonLD/ParserTest.php @@ -27,6 +27,7 @@ use PHPUnit\Framework\TestCase; use Prophecy\PhpUnit\ProphecyTrait; use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser; use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Address; +use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Media; use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\OpeningHours; /** @@ -43,9 +44,11 @@ class ParserTest extends TestCase { $openingHours = $this->prophesize(OpeningHours::class); $address = $this->prophesize(Address::class); + $media = $this->prophesize(Media::class); $subject = new Parser( $openingHours->reveal(), - $address->reveal() + $address->reveal(), + $media->reveal() ); self::assertInstanceOf(Parser::class, $subject); @@ -58,9 +61,11 @@ class ParserTest extends TestCase { $openingHours = $this->prophesize(OpeningHours::class); $address = $this->prophesize(Address::class); + $media = $this->prophesize(Media::class); $subject = new Parser( $openingHours->reveal(), - $address->reveal() + $address->reveal(), + $media->reveal() ); $result = $subject->getId([ @@ -77,9 +82,11 @@ class ParserTest extends TestCase { $openingHours = $this->prophesize(OpeningHours::class); $address = $this->prophesize(Address::class); + $media = $this->prophesize(Media::class); $subject = new Parser( $openingHours->reveal(), - $address->reveal() + $address->reveal(), + $media->reveal() ); $result = $subject->getManagerId([ @@ -99,9 +106,11 @@ class ParserTest extends TestCase { $openingHours = $this->prophesize(OpeningHours::class); $address = $this->prophesize(Address::class); + $media = $this->prophesize(Media::class); $subject = new Parser( $openingHours->reveal(), - $address->reveal() + $address->reveal(), + $media->reveal() ); $result = $subject->getTitle($jsonLD, $language); @@ -224,9 +233,11 @@ class ParserTest extends TestCase { $openingHours = $this->prophesize(OpeningHours::class); $address = $this->prophesize(Address::class); + $media = $this->prophesize(Media::class); $subject = new Parser( $openingHours->reveal(), - $address->reveal() + $address->reveal(), + $media->reveal() ); $result = $subject->getDescription($jsonLD, $language); @@ -348,9 +359,11 @@ class ParserTest extends TestCase { $openingHours = $this->prophesize(OpeningHours::class); $address = $this->prophesize(Address::class); + $media = $this->prophesize(Media::class); $subject = new Parser( $openingHours->reveal(), - $address->reveal() + $address->reveal(), + $media->reveal() ); $result = $subject->getContainedInPlaceIds([ @@ -379,9 +392,11 @@ class ParserTest extends TestCase { $openingHours = $this->prophesize(OpeningHours::class); $address = $this->prophesize(Address::class); + $media = $this->prophesize(Media::class); $subject = new Parser( $openingHours->reveal(), - $address->reveal() + $address->reveal(), + $media->reveal() ); $result = $subject->getLanguages([ @@ -415,9 +430,11 @@ class ParserTest extends TestCase { $openingHours = $this->prophesize(OpeningHours::class); $address = $this->prophesize(Address::class); + $media = $this->prophesize(Media::class); $subject = new Parser( $openingHours->reveal(), - $address->reveal() + $address->reveal(), + $media->reveal() ); $this->expectExceptionCode(1612367481); @@ -438,9 +455,11 @@ class ParserTest extends TestCase { $openingHours = $this->prophesize(OpeningHours::class); $address = $this->prophesize(Address::class); + $media = $this->prophesize(Media::class); $subject = new Parser( $openingHours->reveal(), - $address->reveal() + $address->reveal(), + $media->reveal() ); $result = $subject->getLanguages([]); @@ -473,9 +492,11 @@ class ParserTest extends TestCase $openingHours = $this->prophesize(OpeningHours::class); $openingHours->get($jsonLD)->willReturn($generatedOpeningHours); $address = $this->prophesize(Address::class); + $media = $this->prophesize(Media::class); $subject = new Parser( $openingHours->reveal(), - $address->reveal() + $address->reveal(), + $media->reveal() ); $result = $subject->getOpeningHours($jsonLD); @@ -509,14 +530,72 @@ class ParserTest extends TestCase $openingHours = $this->prophesize(OpeningHours::class); $address = $this->prophesize(Address::class); $address->get($jsonLD)->willReturn($generatedAddress); + $media = $this->prophesize(Media::class); $subject = new Parser( $openingHours->reveal(), - $address->reveal() + $address->reveal(), + $media->reveal() ); $result = $subject->getAddress($jsonLD); self::assertSame($generatedAddress, $result); } + + /** + * @test + */ + public function returnsMedia(): void + { + $jsonLD = [ + 'schema:photo' => [ + '@id' => 'https://thuecat.org/resources/dms_5099196', + ], + 'schema:image' => [ + '@id' => 'https://thuecat.org/resources/dms_5099196', + ], + ]; + $generatedMedia = [ + [ + 'mainImage' => true, + 'type' => 'image', + 'title' => 'Erfurt-Alte Synagoge', + 'description' => 'Frontaler Blick auf die Hausfront/Hausfassade im Innenhof mit Zugang über die Waagegasse', + 'url' => 'https://cms.thuecat.org/o/adaptive-media/image/5099196/Preview-1280x0/image', + 'copyrightYear' => 2009, + 'license' => [ + 'type' => 'https://creativecommons.org/licenses/by/4.0/', + 'author' => 'F:\Bilddatenbank\Museen und Ausstellungen\Alte Synagoge', + ], + ], + [ + 'mainImage' => false, + 'type' => 'image', + 'title' => 'Erfurt-Alte Synagoge', + 'description' => 'Frontaler Blick auf die Hausfront/Hausfassade im Innenhof mit Zugang über die Waagegasse', + 'url' => 'https://cms.thuecat.org/o/adaptive-media/image/5099196/Preview-1280x0/image', + 'copyrightYear' => 2009, + 'license' => [ + 'type' => 'https://creativecommons.org/licenses/by/4.0/', + 'author' => 'F:\Bilddatenbank\Museen und Ausstellungen\Alte Synagoge', + ], + ], + ]; + + $openingHours = $this->prophesize(OpeningHours::class); + $address = $this->prophesize(Address::class); + $media = $this->prophesize(Media::class); + $media->get($jsonLD)->willReturn($generatedMedia); + + $subject = new Parser( + $openingHours->reveal(), + $address->reveal(), + $media->reveal() + ); + + $result = $subject->getMedia($jsonLD); + + self::assertSame($generatedMedia, $result); + } } diff --git a/Tests/Unit/Domain/Import/RequestFactoryTest.php b/Tests/Unit/Domain/Import/RequestFactoryTest.php index 69e5197..e222263 100644 --- a/Tests/Unit/Domain/Import/RequestFactoryTest.php +++ b/Tests/Unit/Domain/Import/RequestFactoryTest.php @@ -49,6 +49,6 @@ class RequestFactoryTest extends TestCase $subject = new RequestFactory(); $request = $subject->createRequest('GET', 'https://example.com/resources/333039283321-xxwg'); - self::assertSame('format=jsonId', $request->getUri()->getQuery()); + self::assertSame('format=jsonld', $request->getUri()->getQuery()); } } diff --git a/Tests/Unit/Domain/Model/Frontend/AddressTest.php b/Tests/Unit/Domain/Model/Frontend/AddressTest.php index 56a0b2a..9d112a1 100644 --- a/Tests/Unit/Domain/Model/Frontend/AddressTest.php +++ b/Tests/Unit/Domain/Model/Frontend/AddressTest.php @@ -21,8 +21,8 @@ namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Model\Frontend; * 02110-1301, USA. */ -use WerkraumMedia\ThueCat\Domain\Model\Frontend\Address; use PHPUnit\Framework\TestCase; +use WerkraumMedia\ThueCat\Domain\Model\Frontend\Address; /** * @covers WerkraumMedia\ThueCat\Domain\Model\Frontend\Address @@ -114,6 +114,26 @@ class AddressTest extends TestCase self::assertSame('+49 361 99998', $subject->getFax()); } + /** + * @test + */ + public function returnsLatitude(): void + { + $subject = new Address('{"geo": {"latitude": 50.978765}}'); + + self::assertSame(50.978765, $subject->getLatitute()); + } + + /** + * @test + */ + public function returnsLongitude(): void + { + $subject = new Address('{"geo": {"longitude": 11.029133}}'); + + self::assertSame(11.029133, $subject->getLongitude()); + } + /** * @test */ diff --git a/Tests/Unit/Domain/Model/Frontend/MediaTest.php b/Tests/Unit/Domain/Model/Frontend/MediaTest.php new file mode 100644 index 0000000..a300f3c --- /dev/null +++ b/Tests/Unit/Domain/Model/Frontend/MediaTest.php @@ -0,0 +1,86 @@ + + * + * 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 PHPUnit\Framework\TestCase; +use WerkraumMedia\ThueCat\Domain\Model\Frontend\Media; + +/** + * @covers WerkraumMedia\ThueCat\Domain\Model\Frontend\Media + */ +class MediaTest extends TestCase +{ + /** + * @test + */ + public function canBeCreated(): void + { + $subject = new Media('[]'); + + self::assertInstanceOf(Media::class, $subject); + } + + /** + * @test + */ + public function returnsMainImageIfPresent(): void + { + $subject = new Media('[{"mainImage":false,"type":"image","title":"Erfurt-Dom-und-Severikirche.jpg"},{"mainImage":true,"type":"image","title":"Erfurt-Dom und Severikirche-beleuchtet.jpg"}]'); + + self::assertSame([ + 'mainImage' => true, + 'type' => 'image', + 'title' => 'Erfurt-Dom und Severikirche-beleuchtet.jpg', + ], $subject->getMainImage()); + } + + /** + * @test + */ + public function returnsEmptyArrayAsMainImageFallback(): void + { + $subject = new Media('[]'); + + self::assertSame([], $subject->getMainImage()); + } + + /** + * @test + */ + public function returnsImagesAsArray(): void + { + $subject = new Media('[{"mainImage":false,"type":"image","title":"Erfurt-Dom-und-Severikirche.jpg"},{"mainImage":true,"type":"image","title":"Erfurt-Dom und Severikirche-beleuchtet.jpg"}]'); + + self::assertSame([ + [ + 'mainImage' => false, + 'type' => 'image', + 'title' => 'Erfurt-Dom-und-Severikirche.jpg', + ], + [ + 'mainImage' => true, + 'type' => 'image', + 'title' => 'Erfurt-Dom und Severikirche-beleuchtet.jpg', + ], + ], $subject->getImages()); + } +} diff --git a/ext_tables.sql b/ext_tables.sql index 6153f81..a037a06 100644 --- a/ext_tables.sql +++ b/ext_tables.sql @@ -49,4 +49,5 @@ CREATE TABLE tx_thuecat_tourist_attraction ( description text DEFAULT '' NOT NULL, opening_hours text DEFAULT '' NOT NULL, address text DEFAULT '' NOT NULL, + media text DEFAULT '' NOT NULL, );