Refactor parsing of JSON-LD

Use Symfony components to map incoming JSON onto objects.
Those provide a mapping. They can then be used to fetch the data in a
common way and insert it into the system.

- Handle languages within JsonDecode
  (normalize incoming data based on language)
- Handle Single Value and List of Values within Entities. They will map
  incoming Data to proper Objects. (We now generally transform during
  serialization process if target is array but we got single entity)
- Add missing tests for existing data.
- Finish migration of all existing data, this includes next step
- Provide discriminator to ObjectNormalizer to auto detect target class
  based on "type" property. (Done for now by own registry)
- Combine generated object with current structure for import -> generate
  data array out of it.
- Resolve foreign references to existing entities,
  (images, contentresponsible, etc.)
This commit is contained in:
Daniel Siepmann 2021-08-05 15:18:39 +02:00
parent fb6b494993
commit bfd4c77a17
68 changed files with 3418 additions and 4330 deletions

View file

@ -25,11 +25,11 @@ namespace WerkraumMedia\ThueCat\DependencyInjection;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use WerkraumMedia\ThueCat\Domain\Import\Converter\Registry;
use WerkraumMedia\ThueCat\Domain\Import\Typo3Converter\Registry;
class ConverterPass implements CompilerPassInterface
{
public const TAG = 'thuecat.converter';
public const TAG = 'thuecat.typo3.converter';
public function process(ContainerBuilder $container): void
{
@ -41,9 +41,6 @@ class ConverterPass implements CompilerPassInterface
continue;
}
// Services that implement MyCustomInterface need to be public,
// to be lazy loadable by the registry via $container->get()
// $container->findDefinition($id)->setPublic(true);
$registry->addMethodCall('registerConverter', [$definition]);
}
}

View file

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

View file

@ -1,78 +0,0 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Converter;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use WerkraumMedia\ThueCat\Domain\Import\Importer\LanguageHandling;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser;
use WerkraumMedia\ThueCat\Domain\Import\Model\EntityCollection;
use WerkraumMedia\ThueCat\Domain\Import\Model\GenericEntity;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration;
class Organisation implements Converter
{
/**
* @var Parser
*/
private $parser;
/**
* @var LanguageHandling
*/
private $language;
public function __construct(
Parser $parser,
LanguageHandling $language
) {
$this->parser = $parser;
$this->language = $language;
}
public function convert(array $jsonLD, ImportConfiguration $configuration): EntityCollection
{
$language = $this->language->getDefaultLanguage($configuration->getStoragePid());
$entity = GeneralUtility::makeInstance(
GenericEntity::class,
$configuration->getStoragePid(),
'tx_thuecat_organisation',
0,
$this->parser->getId($jsonLD),
[
'title' => $this->parser->getTitle($jsonLD, $language),
'description' => $this->parser->getDescription($jsonLD, $language),
]
);
$entities = GeneralUtility::makeInstance(EntityCollection::class);
$entities->add($entity);
return $entities;
}
public function canConvert(array $type): bool
{
return array_search('thuecat:TouristMarketingCompany', $type) !== false;
}
}

View file

@ -1,117 +0,0 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Converter;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use WerkraumMedia\ThueCat\Domain\Import\Importer\LanguageHandling;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Offers;
use WerkraumMedia\ThueCat\Domain\Import\Model\EntityCollection;
use WerkraumMedia\ThueCat\Domain\Import\Model\GenericEntity;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration;
use WerkraumMedia\ThueCat\Domain\Repository\Backend\OrganisationRepository;
use WerkraumMedia\ThueCat\Domain\Repository\Backend\TownRepository;
class TouristAttraction implements Converter
{
/**
* @var Parser
*/
private $parser;
/**
* @var Offers
*/
private $parserForOffers;
/**
* @var LanguageHandling
*/
private $language;
/**
* @var OrganisationRepository
*/
private $organisationRepository;
/**
* @var TownRepository
*/
private $townRepository;
public function __construct(
Parser $parser,
Offers $parserForOffers,
LanguageHandling $language,
OrganisationRepository $organisationRepository,
TownRepository $townRepository
) {
$this->parser = $parser;
$this->parserForOffers = $parserForOffers;
$this->language = $language;
$this->organisationRepository = $organisationRepository;
$this->townRepository = $townRepository;
}
public function convert(array $jsonLD, ImportConfiguration $configuration): EntityCollection
{
$manager = $this->organisationRepository->findOneByRemoteId($this->parser->getManagerId($jsonLD));
$town = $this->townRepository->findOneByRemoteIds($this->parser->getContainedInPlaceIds($jsonLD));
$entities = GeneralUtility::makeInstance(EntityCollection::class);
$storagePid = $configuration->getStoragePid();
foreach ($this->language->getLanguages($storagePid) as $language) {
$title = $this->parser->getTitle($jsonLD, $language);
if ($title === '') {
continue;
}
$entity = GeneralUtility::makeInstance(
GenericEntity::class,
$storagePid,
'tx_thuecat_tourist_attraction',
$language->getLanguageId(),
$this->parser->getId($jsonLD),
[
'title' => $this->parser->getTitle($jsonLD, $language),
'description' => $this->parser->getDescription($jsonLD, $language),
'managed_by' => $manager ? $manager->getUid() : 0,
'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)),
'offers' => json_encode($this->parserForOffers->get($jsonLD, $language)),
]
);
$entities->add($entity);
}
return $entities;
}
public function canConvert(array $type): bool
{
return array_search('schema:TouristAttraction', $type) !== false;
}
}

View file

@ -0,0 +1,201 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Entity;
use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\ForeignReference;
class Base
{
/**
* URL to the original source at ThüCAT.
* Not unique within our system. We have one entity per language,
* while ThüCAT has a single entity containing all languages.
*
* @var string
*/
protected $id = '';
/**
* Short name of the thing.
* Can be translated.
*
* @var string
*/
protected $name = '';
/**
* Long text describing the thing.
* Can be translated.
*
* @var string
*/
protected $description = '';
/**
* URL to official version of this thing outside of ThüCAT.
*
* @var string
*/
protected $url = '';
/**
* @var ForeignReference
*/
protected $photo;
/**
* Images of this Thing.
*
* @var ForeignReference[]
*/
protected $images = [];
/**
* The Thing responsible for the data within this Thing.
*
* @var ForeignReference
*/
protected $managedBy;
public function getId(): string
{
return $this->id;
}
public function hasName(): bool
{
return trim($this->name) !== '';
}
public function getName(): string
{
return $this->name;
}
public function getDescription(): string
{
return $this->description;
}
public function getUrl(): string
{
return $this->url;
}
public function getPhoto(): ?ForeignReference
{
return $this->photo;
}
/**
* @return ForeignReference[]
*/
public function getImages(): array
{
return $this->images;
}
public function getManagedBy(): ?ForeignReference
{
return $this->managedBy;
}
/**
* @internal for mapping via Symfony component.
*/
public function setId(string $url): void
{
$this->id = $url;
}
/**
* @internal for mapping via Symfony component.
*/
public function setName(string $name): void
{
$this->name = $name;
}
/**
* @internal for mapping via Symfony component.
*/
public function setDescription(string $description): void
{
$this->description = $description;
}
/**
* @internal for mapping via Symfony component.
*/
public function setUrl(string $url): void
{
$this->url = $url;
}
/**
* @internal for mapping via Symfony component.
*/
public function setPhoto(ForeignReference $photo): void
{
$this->photo = $photo;
}
/**
* @internal for mapping via Symfony component.
* @return ForeignReference[]
*/
public function getImage(): array
{
return $this->images;
}
/**
* @internal for mapping via Symfony component.
*/
public function addImage(ForeignReference $image): void
{
$this->images[] = $image;
}
/**
* @internal for mapping via Symfony component.
*/
public function removeImage(ForeignReference $image): void
{
}
/**
* @internal for mapping via Symfony component.
*/
public function setContentResponsible(ForeignReference $contentResponsible): void
{
$this->managedBy = $contentResponsible;
}
// TODO: Address
// TODO: Offers
// TODO: containedInPlace -> resolve to town, etc.
}

View file

@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Entity;
/**
* Has to be implemented by Entities to define which types they support.
* Used to detect which Entity should be used for mapping of incoming type.
*/
interface MapsToType
{
/**
* Supported types as provided by API, e.g.:
* - schema:TouristAttraction
* - thuecat:TouristInformation
* - thuecat:Town
* -
* @return string[]
*/
public static function getSupportedTypes(): array;
}

View file

@ -0,0 +1,162 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Entity;
class MediaObject implements MapsToType
{
/**
* @var string
*/
protected $name = '';
/**
* @var string
*/
protected $description = '';
/**
* @var string
*/
protected $url = '';
/**
* @var int
*/
protected $copyrightYear = 0;
/**
* @var string
*/
protected $license = '';
/**
* @var string
*/
protected $licenseAuthor = '';
/**
* @var string
*/
protected $type = '';
public function getName(): string
{
return $this->name;
}
public function getDescription(): string
{
return $this->description;
}
public function getUrl(): string
{
return $this->url;
}
public function getCopyrightYear(): int
{
return $this->copyrightYear;
}
public function getLicense(): string
{
return $this->license;
}
public function getLicenseAuthor(): string
{
return $this->licenseAuthor;
}
public function getType(): string
{
return $this->type;
}
/**
* @internal for mapping via Symfony component.
*/
public function setName(string $name): void
{
$this->name = $name;
}
/**
* @internal for mapping via Symfony component.
*/
public function setDescription(string $description): void
{
$this->description = $description;
}
/**
* @internal for mapping via Symfony component.
*/
public function setUrl(string $url): void
{
$this->url = $url;
}
/**
* @internal for mapping via Symfony component.
*/
public function setCopyrightYear(string $copyrightYear): void
{
$this->copyrightYear = (int) $copyrightYear;
}
/**
* @internal for mapping via Symfony component.
*/
public function setLicense(string $license): void
{
$this->license = $license;
}
/**
* @internal for mapping via Symfony component.
*/
public function setLicenseAuthor(string $licenseAuthor): void
{
$this->licenseAuthor = $licenseAuthor;
}
/**
* @internal for mapping via Symfony component.
*/
public function setType(array $type): void
{
if (in_array('schema:ImageObject', $type)) {
$this->type = 'image';
}
}
public static function getSupportedTypes(): array
{
return [
'schema:MediaObject',
];
}
}

View file

@ -0,0 +1,137 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Entity;
use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\Address;
use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\ForeignReference;
use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\Geo;
use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\OpeningHour;
use WerkraumMedia\ThueCat\Domain\Import\Entity\Shared\Organization;
class Place extends Base
{
use Organization;
/**
* @var Address
*/
protected $address;
/**
* @var Geo
*/
protected $geo;
/**
* @var OpeningHour[]
*/
protected $openingHours = [];
/**
* @var ForeignReference[]
*/
protected $containedInPlace = [];
public function getAddress(): ?Address
{
return $this->address;
}
public function getGeo(): ?Geo
{
return $this->geo;
}
/**
* @return ForeignReference[]
*/
public function getContainedInPlaces(): array
{
return $this->containedInPlace;
}
/**
* @internal for mapping via Symfony component.
*/
public function setAddress(Address $address): void
{
$this->address = $address;
}
/**
* @internal for mapping via Symfony component.
*/
public function setGeo(Geo $geo): void
{
$this->geo = $geo;
}
/**
* @return OpeningHour[]
* @internal for mapping via Symfony component.
*/
public function getOpeningHoursSpecification(): array
{
return $this->openingHours;
}
/**
* @internal for mapping via Symfony component.
*/
public function addOpeningHoursSpecification(OpeningHour $openingHour): void
{
$this->openingHours[] = $openingHour;
}
/**
* @internal for mapping via Symfony component.
*/
public function removeOpeningHoursSpecification(OpeningHour $openingHour): void
{
}
/**
* @return ForeignReference[]
* @internal for mapping via Symfony component.
*/
public function getContainedInPlace(): array
{
return $this->containedInPlace;
}
/**
* @internal for mapping via Symfony component.
*/
public function addContainedInPlace(ForeignReference $place): void
{
$this->containedInPlace[] = $place;
}
/**
* @internal for mapping via Symfony component.
*/
public function removeContainedInPlace(ForeignReference $place): void
{
}
}

View file

@ -0,0 +1,135 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Entity\Properties;
class Address
{
/**
* @var string
*/
protected $streetAddress = '';
/**
* @var string
*/
protected $addressLocality = '';
/**
* @var string
*/
protected $postalCode = '';
/**
* @var string
*/
protected $telephone = '';
/**
* @var string
*/
protected $faxNumber = '';
/**
* @var string
*/
protected $email = '';
public function getStreetAddress(): string
{
return $this->streetAddress;
}
public function getAddressLocality(): string
{
return $this->addressLocality;
}
public function getPostalCode(): string
{
return $this->postalCode;
}
public function getTelephone(): string
{
return $this->telephone;
}
public function getFaxNumber(): string
{
return $this->faxNumber;
}
public function getEmail(): string
{
return $this->email;
}
/**
* @internal for mapping via Symfony component.
*/
public function setStreetAddress(string $streetAddress): void
{
$this->streetAddress = $streetAddress;
}
/**
* @internal for mapping via Symfony component.
*/
public function setAddressLocality(string $addressLocality): void
{
$this->addressLocality = $addressLocality;
}
/**
* @internal for mapping via Symfony component.
*/
public function setPostalCode(string $postalCode): void
{
$this->postalCode = $postalCode;
}
/**
* @internal for mapping via Symfony component.
*/
public function setTelephone(string $telephone): void
{
$this->telephone = $telephone;
}
/**
* @internal for mapping via Symfony component.
*/
public function setFaxNumber(string $faxNumber): void
{
$this->faxNumber = $faxNumber;
}
/**
* @internal for mapping via Symfony component.
*/
public function setEmail(string $email): void
{
$this->email = $email;
}
}

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
@ -19,30 +21,18 @@
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser;
namespace WerkraumMedia\ThueCat\Domain\Import\Entity\Properties;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
class GenericFields
class DayOfWeek
{
/**
* @var LanguageValues
* @var string
*/
private $languageValues;
protected $dayOfWeek = '';
public function __construct(
LanguageValues $languageValues
string $dayOfWeek
) {
$this->languageValues = $languageValues;
}
public function getTitle(array $jsonLD, SiteLanguage $language): string
{
return $this->languageValues->getValueForLanguage($jsonLD['schema:name'] ?? [], $language);
}
public function getDescription(array $jsonLD, SiteLanguage $language): string
{
return $this->languageValues->getValueForLanguage($jsonLD['schema:description'] ?? [], $language);
$this->dayOfWeek = $dayOfWeek;
}
}

View file

@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Entity\Properties;
/**
* Represents a foreign reference with only id = URL.
* This reference is not resolved.
*/
class ForeignReference
{
/**
* URL to the original source at ThüCAT.
* Not unique within our system. We have one entity per language,
* while ThüCAT has a single entity containing all languages.
*
* @var string
*/
protected $id = '';
public function getId(): string
{
return $this->id;
}
/**
* @internal for mapping via Symfony component.
*/
public function setId(string $id): void
{
$this->id = $id;
}
}

View file

@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Entity\Properties;
class Geo
{
/**
* @var float
*/
protected $longitude = 0.00;
/**
* @var float
*/
protected $latitude = 0.00;
public function getLongitude(): float
{
return $this->longitude;
}
public function getLatitude(): float
{
return $this->latitude;
}
/**
* @internal for mapping via Symfony component.
*/
public function setLongitude(string $longitude): void
{
$this->longitude = (float) $longitude;
}
/**
* @internal for mapping via Symfony component.
*/
public function setLatitude(string $latitude): void
{
$this->latitude = (float) $latitude;
}
}

View file

@ -0,0 +1,100 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Entity\Properties;
class Offer
{
/**
* @var string
*/
protected $name = '';
/**
* @var string
*/
protected $description = '';
/**
* @var PriceSpecification[]
*/
protected $prices = [];
public function getName(): string
{
return $this->name;
}
public function getDescription(): string
{
return $this->description;
}
/**
* @return PriceSpecification[]
*/
public function getPrices(): array
{
return $this->prices;
}
/**
* @internal for mapping via Symfony component.
*/
public function setName(string $name): void
{
$this->name = $name;
}
/**
* @internal for mapping via Symfony component.
*/
public function setDescription(string $description): void
{
$this->description = $description;
}
/**
* @return PriceSpecification[]
* @internal for mapping via Symfony component.
*/
public function getPriceSpecification(): array
{
return $this->prices;
}
/**
* @internal for mapping via Symfony component.
*/
public function addPriceSpecification(PriceSpecification $priceSpecification): void
{
$this->prices[] = $priceSpecification;
}
/**
* @internal for mapping via Symfony component.
*/
public function removePriceSpecification(PriceSpecification $priceSpecification): void
{
}
}

View file

@ -0,0 +1,126 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Entity\Properties;
class OpeningHour
{
/**
* @var \DateTimeImmutable
*/
protected $validFrom;
/**
* @var \DateTimeImmutable
*/
protected $validThrough;
/**
* @var \DateTimeImmutable
*/
protected $opens;
/**
* @var \DateTimeImmutable
*/
protected $closes;
/**
* @var string[]
*/
protected $daysOfWeek = [];
public function getValidFrom(): \DateTimeImmutable
{
return $this->validFrom;
}
public function getValidThrough(): \DateTimeImmutable
{
return $this->validThrough;
}
public function getOpens(): \DateTimeImmutable
{
return $this->opens;
}
public function getCloses(): \DateTimeImmutable
{
return $this->closes;
}
/**
* @return string[]
*/
public function getDaysOfWeek(): array
{
return $this->daysOfWeek;
}
/**
* @internal for mapping via Symfony component.
*/
public function setValidFrom(\DateTimeImmutable $validFrom): void
{
$this->validFrom = $validFrom;
}
/**
* @internal for mapping via Symfony component.
*/
public function setValidThrough(\DateTimeImmutable $validThrough): void
{
$this->validThrough = $validThrough;
}
/**
* @internal for mapping via Symfony component.
*/
public function setOpens(\DateTimeImmutable $opens): void
{
$this->opens = $opens;
}
/**
* @internal for mapping via Symfony component.
*/
public function setCloses(\DateTimeImmutable $closes): void
{
$this->closes = $closes;
}
/**
* @param string|array $dayOfWeek
*/
public function setDayOfWeek($dayOfWeek): void
{
if (is_array($dayOfWeek) === false) {
$dayOfWeek = [$dayOfWeek];
}
$this->daysOfWeek = array_map(function (string $dayOfWeek) {
return mb_substr($dayOfWeek, 7);
}, $dayOfWeek);
}
}

View file

@ -0,0 +1,130 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Entity\Properties;
class PriceSpecification
{
// TODO: Move name to trait
// TODO: Move description to trait
/**
* @var string
*/
protected $name = '';
/**
* @var string
*/
protected $description = '';
/**
* @var float
*/
protected $price = 0.00;
/**
* E.g. 'EUR'
* ThueCat specific format.
*
* @var string
*/
protected $currency = '';
/**
* E.g. 'PerPerson'
* ThueCat specific property.
*
* @var string
*/
protected $calculationRule = '';
public function getName(): string
{
return $this->name;
}
public function getDescription(): string
{
return $this->description;
}
public function getPrice(): float
{
return $this->price;
}
public function getCurrency(): string
{
return $this->currency;
}
public function getCalculationRule(): string
{
return $this->calculationRule;
}
/**
* @internal for mapping via Symfony component.
*/
public function setName(string $name): void
{
$this->name = $name;
}
/**
* @internal for mapping via Symfony component.
*/
public function setDescription(string $description): void
{
$this->description = $description;
}
/**
* @internal for mapping via Symfony component.
*/
public function setPrice(string $price): void
{
$this->price = (float)$price;
}
/**
* @internal for mapping via Symfony component.
*/
public function setPriceCurrency(string $currency): void
{
// TODO: Move to serializer process while decoding json?!
// Check for @type and @value, if type is currency …
$this->currency = str_replace('thuecat:', '', $currency);
}
/**
* @internal for mapping via Symfony component.
*/
public function setCalculationRule(string $calculationRule): void
{
// TODO: Move to serializer process while decoding json?!
// Check for @type and @value, if type is currency …
$this->calculationRule = str_replace('thuecat:', '', $calculationRule);
}
}

View file

@ -0,0 +1,70 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Entity\Shared;
use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\Offer;
/**
* All the Things can be organizations but don't have to be.
* We communicate that by providing a trait which can be used by all those Things.
*/
trait Organization
{
/**
* @var Offer[]
*/
protected $offers = [];
/**
* @return Offer[]
*/
public function getOffers(): array
{
return $this->offers;
}
/**
* @internal for mapping via Symfony component.
* @return Offer[]
*/
public function getMakesOffer(): array
{
return $this->offers;
}
/**
* @internal for mapping via Symfony component.
*/
public function addMakesOffer(Offer $offer): void
{
$this->offers[] = $offer;
}
/**
* @internal for mapping via Symfony component.
*/
public function removeMakesOffer(Offer $offer): void
{
}
}

View file

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

View file

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Entity;
class TouristInformation extends Place implements MapsToType
{
// TODO: Only has title and description which should be moved to trait anyway
public static function getSupportedTypes(): array
{
return [
'thuecat:TouristInformation',
];
}
}

View file

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Entity;
class TouristMarketingCompany extends Base implements MapsToType
{
// TODO: Only has title and description which should be moved to trait anyway
public static function getSupportedTypes(): array
{
return [
'thuecat:TouristMarketingCompany',
];
}
}

View file

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Entity;
class Town extends Base implements MapsToType
{
// TODO: Only has title and description which should be moved to trait anyway
public static function getSupportedTypes(): array
{
return [
'thuecat:Town',
];
}
}

View file

@ -0,0 +1,97 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import;
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\ArrayDenormalizer;
use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\JsonDecode;
use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\MappingException;
class EntityMapper
{
/**
* Returns mapped entity.
* The returned object is of type $targetClassName
*/
public function mapDataToEntity(
array $jsonLD,
string $targetClassName,
array $context
): object {
$serializer = $this->createSerializer();
try {
return $serializer->deserialize(
json_encode($jsonLD),
$targetClassName,
'json',
$context
);
} catch (\Throwable $e) {
throw new MappingException($jsonLD, $targetClassName, $e);
}
}
private function createSerializer(): Serializer
{
return new Serializer(
[
new ArrayDenormalizer(),
new DateTimeNormalizer(),
new ObjectNormalizer(
null,
null,
null,
// We enforce following behaviour:
// 1. Try to fetch info via reflection (e.g. by methods or property)
// 2. Use php doc as fallback
// We do this because of:
// Most of the time we can just use the TypeHint of setter or add/remove for collections
// Sometimes we have to deal with multiple types (e.g. string and array)
// We then can have a different property name and no type hint, reflection will fail
// But we can use PHPDoc to define all supported
new PropertyInfoExtractor(
[],
[
new ReflectionExtractor(),
new PhpDocExtractor(),
]
)
),
],
[
new JsonEncoder(
null,
new JsonDecode()
),
]
);
}
}

View file

@ -0,0 +1,73 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\EntityMapper;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer as SymfonyArrayDenormalizer;
class ArrayDenormalizer extends SymfonyArrayDenormalizer
{
public function denormalize(
$data,
string $type,
string $format = null,
array $context = []
): array {
return parent::denormalize(
$this->transformSingleEntryToMultiEntry($data),
$type,
$format,
$context
);
}
/**
* We sometimes expect an array of object but only get a single object with different structure.
*
* This method detects this and transforms it into an array with this single object to stay compatible.
*
* E.g. schema:image might be an array or single image.
* Our objects always expects an array and serializer would break.
*/
private function transformSingleEntryToMultiEntry(array $data): array
{
// If we got strings, we know this is a single object which needs transformation.
if (self::hasOnlyNumericKeys($data) === false) {
$data = [$data];
}
return $data;
}
public static function hasOnlyNumericKeys(array $data): bool
{
// Each object is identified by an numeric index
// Strings are only used as index for object properties.
$differences = array_diff(
array_keys($data),
array_filter(array_keys($data), 'is_int')
);
return $differences === [];
}
}

View file

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

View file

@ -0,0 +1,215 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\EntityMapper;
use Symfony\Component\Serializer\Encoder\JsonDecode as SymfonyJsonDecode;
use TYPO3\CMS\Core\Utility\StringUtility;
/**
* Used to add further necessary normalization on decoding incoming JSON structure.
*
* See list of decode* methods to see what kind of data is normalized.
*/
class JsonDecode extends SymfonyJsonDecode
{
public const ACTIVE_LANGUAGE = 'active_language';
public function decode(
string $data,
string $format,
array $context = []
) {
$context[self::ASSOCIATIVE] = true;
$result = parent::decode($data, $format, $context);
$activeLanguage = $context[self::ACTIVE_LANGUAGE] ?? '';
if ($activeLanguage === '') {
throw new \InvalidArgumentException('Provide active language: ' . self::ACTIVE_LANGUAGE);
}
return $this->process(
$result,
$activeLanguage
);
}
private function process(
array &$array,
string $activeLanguage
): array {
foreach ($array as $key => $value) {
$value = $this->decodeDateTime($value);
$value = $this->decodeSingleValues($value);
$value = $this->decodeLanguageSpecificValue($value, $activeLanguage);
if (is_array($value)) {
$value = $this->process($value, $activeLanguage);
}
$newKey = $this->mapKey($key);
if ($newKey !== $key) {
unset($array[$key]);
}
$array[$newKey] = $value;
}
return $array;
}
/**
* Some properties might contain a list of value where each list entry is for a specific language.
*
* This decode will resolve the list to a single value based on current language settings from context.
*
* @param mixed $value
* @return mixed
*/
private function decodeLanguageSpecificValue(
&$value,
string $activeLanguage
) {
if (is_array($value) === false) {
return $value;
}
$newValue = $value['@value'] ?? null;
$language = $value['@language'] ?? null;
if (is_string($newValue) && $language === $activeLanguage) {
return $newValue;
}
if (is_string($newValue) && is_string($language) && $language !== $activeLanguage) {
return '';
}
$hasLanguageValue = false;
if (ArrayDenormalizer::hasOnlyNumericKeys($value) === false) {
return $value;
}
foreach ($value as $languageSpecific) {
if (is_array($languageSpecific) === false) {
continue;
}
$language = $languageSpecific['@language'] ?? '';
if ($language === '') {
continue;
}
if ($language === $activeLanguage) {
$newValue = $languageSpecific['@value'] ?? null;
}
if (is_string($newValue)) {
return $newValue;
}
if ($hasLanguageValue === false && isset($languageSpecific['@value'])) {
$hasLanguageValue = true;
}
}
// Prevent delivering original array if we detected this is language specific.
// A string is then expected. But we didn't find any, so return empty one to conform to type.
if ($hasLanguageValue) {
return '';
}
return $value;
}
/**
* Some properties might be an array with extra info.
*
* This decode will resolve single values wrapped in array with extra info.
*
* @param mixed $value
* @return mixed
*/
private function decodeSingleValues(
&$value
) {
if (is_array($value) === false) {
return $value;
}
$newValue = $value['@value'] ?? null;
$language = $value['@language'] ?? null;
if (is_string($newValue) && $language === null) {
return $newValue;
}
return $value;
}
/**
* Prepare data structure for PHP \DateTimeImmutable.
*
* @param mixed $value
* @return mixed
*/
private function decodeDateTime(
&$value
) {
$supportedTypes = [
'schema:Time',
'schema:Date',
];
if (
is_array($value) === false
|| isset($value['@type']) === false
|| isset($value['@value']) === false
|| in_array($value['@type'], $supportedTypes) === false
) {
return $value;
}
return $value['@value'];
}
/**
* @param mixed $key
* @return mixed
*/
private function mapKey($key)
{
if (is_string($key) === false) {
return $key;
}
if (StringUtility::beginsWith($key, '@')) {
return mb_substr($key, 1);
}
if (StringUtility::beginsWith($key, 'schema:')) {
return mb_substr($key, 7);
}
if (StringUtility::beginsWith($key, 'thuecat:')) {
return mb_substr($key, 8);
}
return $key;
}
}

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
@ -19,34 +21,31 @@
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Importer;
namespace WerkraumMedia\ThueCat\Domain\Import\EntityMapper;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use TYPO3\CMS\Core\Site\SiteFinder;
class LanguageHandling
class MappingException extends \Exception
{
/**
* @var SiteFinder
* @var array
*/
private $siteFinder;
public function __construct(
SiteFinder $siteFinder
) {
$this->siteFinder = $siteFinder;
}
protected $jsonLD = [];
/**
* @return SiteLanguage[]
* @var string
*/
public function getLanguages(int $pageUid): array
{
return $this->siteFinder->getSiteByPageId($pageUid)->getLanguages();
}
protected $targetClassName = '';
public function getDefaultLanguage(int $pageUid): SiteLanguage
{
return $this->siteFinder->getSiteByPageId($pageUid)->getDefaultLanguage();
public function __construct(
array $jsonLD,
string $targetClassName,
\Throwable $previous
) {
parent::__construct(
'Could not map incoming JSON-LD to target object: ' . $previous->getMessage(),
1628157659,
$previous
);
$this->jsonLD = $jsonLD;
$this->targetClassName = $targetClassName;
}
}

View file

@ -24,10 +24,14 @@ declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Import;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use WerkraumMedia\ThueCat\Domain\Import\Converter\Converter;
use WerkraumMedia\ThueCat\Domain\Import\Converter\Registry as ConverterRegistry;
use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\EntityRegistry;
use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\JsonDecode;
use WerkraumMedia\ThueCat\Domain\Import\Entity\MapsToType;
use WerkraumMedia\ThueCat\Domain\Import\Importer\Converter;
use WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData;
use WerkraumMedia\ThueCat\Domain\Import\Importer\Languages;
use WerkraumMedia\ThueCat\Domain\Import\Importer\SaveData;
use WerkraumMedia\ThueCat\Domain\Import\Model\EntityCollection;
use WerkraumMedia\ThueCat\Domain\Import\UrlProvider\Registry as UrlProviderRegistry;
use WerkraumMedia\ThueCat\Domain\Import\UrlProvider\UrlProvider;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration;
@ -42,10 +46,25 @@ class Importer
private $urls;
/**
* @var ConverterRegistry
* @var Converter
*/
private $converter;
/**
* @var EntityRegistry
*/
private $entityRegistry;
/**
* @var EntityMapper
*/
private $entityMapper;
/**
* @var Languages
*/
private $languages;
/**
* @var FetchData
*/
@ -73,13 +92,19 @@ class Importer
public function __construct(
UrlProviderRegistry $urls,
ConverterRegistry $converter,
Converter $converter,
EntityRegistry $entityRegistry,
EntityMapper $entityMapper,
Languages $languages,
ImportLogRepository $importLogRepository,
FetchData $fetchData,
SaveData $saveData
) {
$this->urls = $urls;
$this->converter = $converter;
$this->entityRegistry = $entityRegistry;
$this->entityMapper = $entityMapper;
$this->languages = $languages;
$this->importLogRepository = $importLogRepository;
$this->fetchData = $fetchData;
$this->saveData = $saveData;
@ -119,11 +144,39 @@ class Importer
private function importJsonEntity(array $jsonEntity): void
{
$converter = $this->converter->getConverterBasedOnType($jsonEntity['@type']);
if ($converter instanceof Converter) {
$entities = $converter->convert($jsonEntity, $this->configuration);
$this->saveData->import($entities, $this->importLog);
$targetEntity = $this->entityRegistry->getEntityByTypes($jsonEntity['@type']);
if ($targetEntity === '') {
return;
}
$entities = new EntityCollection();
foreach ($this->languages->getAvailable($this->configuration) as $language) {
$mappedEntity = $this->entityMapper->mapDataToEntity(
$jsonEntity,
$targetEntity,
[
JsonDecode::ACTIVE_LANGUAGE => $language,
]
);
if (!$mappedEntity instanceof MapsToType) {
continue;
}
$convertedEntity = $this->converter->convert(
$mappedEntity,
$this->configuration,
$language
);
if ($convertedEntity === null) {
continue;
}
$entities->add($convertedEntity);
}
$this->saveData->import(
$entities,
$this->importLog
);
}
}

View file

@ -21,22 +21,23 @@ declare(strict_types=1);
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Converter;
namespace WerkraumMedia\ThueCat\Domain\Import\Importer;
use WerkraumMedia\ThueCat\Domain\Import\Model\EntityCollection;
use WerkraumMedia\ThueCat\Domain\Import\Entity\MapsToType;
use WerkraumMedia\ThueCat\Domain\Import\Model\Entity;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration;
interface Converter
{
/**
* A single type is an array of different types.
* All types together identify a specific entity and possible converter.
* Receives the incoming JSON-LD mapped to objects.
* Should convert that one for the actual system, e.g. TYPO3.
*
* @param string $language The current language, e.g. 'de', 'en', 'fr'
*/
public function canConvert(array $type): bool;
/**
* A single JSONLD entity can have multiple languages.
* That may result in multiple entities in TYPO3.
*/
public function convert(array $jsonLD, ImportConfiguration $configuration): EntityCollection;
public function convert(
MapsToType $mapped,
ImportConfiguration $configuration,
string $language
): ?Entity;
}

View file

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

View file

@ -1,120 +0,0 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\JsonLD;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Address;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\GenericFields;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Media;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\OpeningHours;
class Parser
{
/**
* @var GenericFields
*/
private $genericFields;
/**
* @var OpeningHours
*/
private $openingHours;
/**
* @var Address
*/
private $address;
/**
* @var Media
*/
private $media;
public function __construct(
GenericFields $genericFields,
OpeningHours $openingHours,
Address $address,
Media $media
) {
$this->genericFields = $genericFields;
$this->openingHours = $openingHours;
$this->address = $address;
$this->media = $media;
}
public function getId(array $jsonLD): string
{
return $jsonLD['@id'];
}
public function getTitle(array $jsonLD, SiteLanguage $language): string
{
return $this->genericFields->getTitle($jsonLD, $language);
}
public function getDescription(array $jsonLD, SiteLanguage $language): string
{
return $this->genericFields->getDescription($jsonLD, $language);
}
public function getManagerId(array $jsonLD): string
{
return $jsonLD['thuecat:contentResponsible']['@id'];
}
/**
* @return string[]
*/
public function getContainedInPlaceIds(array $jsonLD): array
{
if (isset($jsonLD['schema:containedInPlace']['@id'])) {
return [
$jsonLD['schema:containedInPlace']['@id'],
];
}
if (isset($jsonLD['schema:containedInPlace']) === false) {
return [];
}
return array_map(function (array $place) {
return $place['@id'];
}, $jsonLD['schema:containedInPlace']);
}
public function getOpeningHours(array $jsonLD): array
{
return $this->openingHours->get($jsonLD);
}
public function getAddress(array $jsonLD): array
{
return $this->address->get($jsonLD);
}
public function getMedia(array $jsonLD): array
{
return $this->media->get($jsonLD);
}
}

View file

@ -1,79 +0,0 @@
<?php
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser;
class Address
{
public function get(array $jsonLD): array
{
$address = $jsonLD['schema:address'] ?? [];
$geo = $jsonLD['schema:geo'] ?? [];
return [
'street' => $this->getStreet($address),
'zip' => $this->getZip($address),
'city' => $this->getCity($address),
'email' => $this->getEmail($address),
'phone' => $this->getPhone($address),
'fax' => $this->getFax($address),
'geo' => $this->getGeo($geo),
];
}
private function getStreet(array $address): string
{
return $address['schema:streetAddress']['@value'] ?? '';
}
private function getZip(array $address): string
{
return $address['schema:postalCode']['@value'] ?? '';
}
private function getCity(array $address): string
{
return $address['schema:addressLocality']['@value'] ?? '';
}
private function getEmail(array $address): string
{
return $address['schema:email']['@value'] ?? '';
}
private function getPhone(array $address): string
{
return $address['schema:telephone']['@value'] ?? '';
}
private function getFax(array $address): string
{
return $address['schema:faxNumber']['@value'] ?? '';
}
private function getGeo(array $geo): array
{
return [
'latitude' => floatval($geo['schema:latitude']['@value'] ?? 0.0),
'longitude' => floatval($geo['schema:longitude']['@value'] ?? 0.0),
];
}
}

View file

@ -1,61 +0,0 @@
<?php
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
class LanguageValues
{
public function getValueForLanguage(
array $property,
SiteLanguage $language
): string {
if (
isset($property['@value'])
&& $this->doesLanguageMatch($property, $language)
) {
return $property['@value'];
}
foreach ($property as $languageEntry) {
if (
is_array($languageEntry)
&& $this->doesLanguageMatch($languageEntry, $language)
) {
return $languageEntry['@value'];
}
}
return '';
}
private function doesLanguageMatch(
array $property,
SiteLanguage $language
): bool {
$isoCode = $language->getTwoLetterIsoCode();
return isset($property['@language'])
&& $property['@language'] === $isoCode
;
}
}

View file

@ -1,134 +0,0 @@
<?php
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser;
use WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData;
use WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData\InvalidResponseException;
class Media
{
/**
* @var FetchData
*/
private $fetchData;
public function __construct(
FetchData $fetchData
) {
$this->fetchData = $fetchData;
}
public function get(array $jsonLD): array
{
$media = [];
$media = $this->addMainImage($jsonLD, $media);
$media = $this->addSingleImage($jsonLD, $media);
$media = $this->addImages($jsonLD, $media);
return $media;
}
private function addMainImage(array $jsonLD, array $media): array
{
if (isset($jsonLD['schema:photo']['@id']) === false) {
return $media;
}
try {
$media[] = array_merge(
[
'mainImage' => true,
],
$this->getMedia($jsonLD['schema:photo']['@id'])
);
} catch (InvalidResponseException $e) {
// Nothing todo
}
return $media;
}
private function addSingleImage(array $jsonLD, array $media): array
{
if (isset($jsonLD['schema:image']['@id']) === false) {
return $media;
}
try {
$media[] = array_merge(
[
'mainImage' => false,
],
$this->getMedia($jsonLD['schema:image']['@id'])
);
} catch (InvalidResponseException $e) {
// Nothing todo
}
return $media;
}
private function addImages(array $jsonLD, array $media): array
{
if (
isset($jsonLD['schema:image']) === false
|| isset($jsonLD['schema:image']['@id'])
|| is_array($jsonLD['schema:image']) === false
) {
return $media;
}
foreach ($jsonLD['schema:image'] as $image) {
try {
$media[] = array_merge(
[
'mainImage' => false,
],
$this->getMedia($image['@id'])
);
} catch (InvalidResponseException $e) {
// Nothing todo
}
}
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'] ?? '',
],
];
}
}

View file

@ -1,121 +0,0 @@
<?php
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
class Offers
{
/**
* @var GenericFields
*/
private $genericFields;
public function __construct(
GenericFields $genericFields
) {
$this->genericFields = $genericFields;
}
public function get(array $jsonLD, SiteLanguage $language): array
{
$offers = [];
$jsonLDOffers = $jsonLD['schema:makesOffer'] ?? [];
if (isset($jsonLDOffers['@id'])) {
return [
$this->getOffer($jsonLDOffers, $language),
];
}
foreach ($jsonLDOffers as $jsonLDOffer) {
$offer = $this->getOffer($jsonLDOffer, $language);
if ($offer !== []) {
$offers[] = $offer;
}
}
return $offers;
}
private function getOffer(array $jsonLD, SiteLanguage $language): array
{
return [
'title' => $this->genericFields->getTitle($jsonLD, $language),
'description' => $this->genericFields->getDescription($jsonLD, $language),
'prices' => $this->getPrices($jsonLD, $language),
];
}
private function getPrices(array $jsonLD, SiteLanguage $language): array
{
$prices = [];
$jsonLDPrices = $jsonLD['schema:priceSpecification'] ?? [];
if (isset($jsonLDPrices['@id'])) {
return [
$this->getPrice($jsonLDPrices, $language),
];
}
foreach ($jsonLDPrices as $jsonLDPrice) {
$price = $this->getPrice($jsonLDPrice, $language);
if ($price !== []) {
$prices[] = $price;
}
}
return $prices;
}
private function getPrice(array $jsonLD, SiteLanguage $language): array
{
return [
'title' => $this->genericFields->getTitle($jsonLD, $language),
'description' => $this->genericFields->getDescription($jsonLD, $language),
'price' => $this->getPriceValue($jsonLD),
'currency' => $this->getCurrencyValue($jsonLD),
'rule' => $this->getRuleValue($jsonLD),
];
}
private function getPriceValue(array $jsonLD): float
{
$price = $jsonLD['schema:price']['@value'] ?? 0.0;
$price = floatval($price);
return $price;
}
private function getCurrencyValue(array $jsonLD): string
{
$currency = $jsonLD['schema:priceCurrency']['@value'] ?? '';
$currency = str_replace('thuecat:', '', $currency);
return $currency;
}
private function getRuleValue(array $jsonLD): string
{
$rule = $jsonLD['thuecat:calculationRule']['@value'] ?? '';
$rule = str_replace('thuecat:', '', $rule);
return $rule;
}
}

View file

@ -1,102 +0,0 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser;
class OpeningHours
{
public function get(array $jsonLD): array
{
$openingHours = $jsonLD['schema:openingHoursSpecification'] ?? [];
if ($openingHours === []) {
return [];
}
if (isset($openingHours['@id'])) {
return [$this->parseSingleEntry($openingHours)];
}
return array_values(array_map([$this, 'parseSingleEntry'], $openingHours));
}
private function parseSingleEntry(array $openingHour): array
{
return [
'opens' => $this->getOpens($openingHour),
'closes' => $this->getCloses($openingHour),
'from' => $this->getFrom($openingHour),
'through' => $this->getThrough($openingHour),
'daysOfWeek' => $this->getDaysOfWeek($openingHour),
];
}
private function getOpens(array $openingHour): string
{
return $openingHour['schema:opens']['@value'] ?? '';
}
private function getCloses(array $openingHour): string
{
return $openingHour['schema:closes']['@value'] ?? '';
}
private function getFrom(array $openingHour): ?\DateTimeImmutable
{
if (isset($openingHour['schema:validFrom']['@value'])) {
return new \DateTimeImmutable($openingHour['schema:validFrom']['@value']);
}
return null;
}
private function getThrough(array $openingHour): ?\DateTimeImmutable
{
if (isset($openingHour['schema:validThrough']['@value'])) {
return new \DateTimeImmutable($openingHour['schema:validThrough']['@value']);
}
return null;
}
private function getDaysOfWeek(array $openingHour): array
{
if (isset($openingHour['schema:dayOfWeek']['@value'])) {
return [$this->getDayOfWeekString($openingHour['schema:dayOfWeek']['@value'])];
}
$daysOfWeek = array_map(function ($dayOfWeek) {
return $this->getDayOfWeekString($dayOfWeek['@value']);
}, $openingHour['schema:dayOfWeek'] ?? []);
sort($daysOfWeek);
return $daysOfWeek;
}
private function getDayOfWeekString(string $jsonLDValue): string
{
return str_replace(
'schema:',
'',
$jsonLDValue
);
}
}

View file

@ -0,0 +1,81 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import;
use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\EntityRegistry;
use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\JsonDecode;
use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\ForeignReference;
use WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData;
class ResolveForeignReference
{
/**
* @var FetchData
*/
private $fetchData;
/**
* @var EntityRegistry
*/
private $entityRegistry;
/**
* @var EntityMapper
*/
private $entityMapper;
public function __construct(
FetchData $fetchData,
EntityRegistry $entityRegistry,
EntityMapper $entityMapper
) {
$this->fetchData = $fetchData;
$this->entityRegistry = $entityRegistry;
$this->entityMapper = $entityMapper;
}
public function resolve(
ForeignReference $foreignReference,
string $language
): ?object {
$jsonLD = $this->fetchData->jsonLDFromUrl($foreignReference->getId());
$jsonEntity = $jsonLD['@graph'][0] ?? null;
if ($jsonEntity === null) {
return null;
}
$targetEntity = $this->entityRegistry->getEntityByTypes($jsonEntity['@type']);
if ($targetEntity === '') {
return null;
}
return $this->entityMapper->mapDataToEntity(
$jsonEntity,
$targetEntity,
[
JsonDecode::ACTIVE_LANGUAGE => $language,
]
);
}
}

View file

@ -0,0 +1,64 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import;
use WerkraumMedia\ThueCat\Domain\Import\Entity\MapsToType;
use WerkraumMedia\ThueCat\Domain\Import\Importer\Converter;
use WerkraumMedia\ThueCat\Domain\Import\Model\Entity;
use WerkraumMedia\ThueCat\Domain\Import\Typo3Converter\Converter as Typo3ConcreteConverter;
use WerkraumMedia\ThueCat\Domain\Import\Typo3Converter\Registry;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration;
class Typo3Converter implements Converter
{
/**
* @var Registry
*/
private $registry;
public function __construct(
Registry $registry
) {
$this->registry = $registry;
}
public function convert(
MapsToType $mapped,
ImportConfiguration $configuration,
string $language
): ?Entity {
$concreteConverter = $this->registry->getConverterBasedOnType($mapped);
if (!$concreteConverter instanceof Typo3ConcreteConverter) {
throw new \Exception(
'No TYPO3 Converter registered for given Entity "' . get_class($mapped) . '".',
1628244329
);
}
return $concreteConverter->convert(
$mapped,
$configuration,
$language
);
}
}

View file

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

View file

@ -0,0 +1,82 @@
<?php
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Typo3Converter;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use TYPO3\CMS\Core\Site\SiteFinder;
use WerkraumMedia\ThueCat\Domain\Import\Importer\Languages;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration;
class LanguageHandling implements Languages
{
/**
* @var SiteFinder
*/
private $siteFinder;
public function __construct(
SiteFinder $siteFinder
) {
$this->siteFinder = $siteFinder;
}
public function getAvailable(ImportConfiguration $configuration): array
{
return array_map(function (SiteLanguage $language) {
return $language->getTwoLetterIsoCode();
}, $this->getLanguages($configuration->getStoragePid()));
}
public function getLanguageUidForString(int $pageUid, string $isoCode): int
{
$languages = $this->siteFinder->getSiteByPageId($pageUid)->getLanguages();
foreach ($languages as $language) {
if ($language->getTwoLetterIsoCode() === $isoCode) {
return $language->getLanguageId();
}
}
throw new \InvalidArgumentException(
sprintf(
'Could not find language for combination of page "%d" and iso code "%s".',
$pageUid,
$isoCode
),
1628246493
);
}
// TODO: Check usages and remove below methods
/**
* @return SiteLanguage[]
*/
public function getLanguages(int $pageUid): array
{
return $this->siteFinder->getSiteByPageId($pageUid)->getLanguages();
}
public function getDefaultLanguage(int $pageUid): SiteLanguage
{
return $this->siteFinder->getSiteByPageId($pageUid)->getDefaultLanguage();
}
}

View file

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

View file

@ -21,7 +21,9 @@ declare(strict_types=1);
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Converter;
namespace WerkraumMedia\ThueCat\Domain\Import\Typo3Converter;
use WerkraumMedia\ThueCat\Domain\Import\Entity\MapsToType;
/**
* Central registry of all available converters.
@ -38,10 +40,10 @@ class Registry
$this->converters[] = $converter;
}
public function getConverterBasedOnType(array $type): ?Converter
public function getConverterBasedOnType(MapsToType $entity): ?Converter
{
foreach ($this->converters as $converter) {
if ($converter->canConvert($type)) {
if ($converter->canConvert($entity)) {
return $converter;
}
}

View file

@ -0,0 +1,237 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Typo3Converter;
use WerkraumMedia\ThueCat\Domain\Import\Entity\MapsToType;
use WerkraumMedia\ThueCat\Domain\Import\Entity\MediaObject;
use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\ForeignReference;
use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\PriceSpecification;
use WerkraumMedia\ThueCat\Domain\Import\Entity\TouristAttraction as TouristAttractionEntity;
use WerkraumMedia\ThueCat\Domain\Import\Model\Entity;
use WerkraumMedia\ThueCat\Domain\Import\Model\GenericEntity;
use WerkraumMedia\ThueCat\Domain\Import\ResolveForeignReference;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration;
use WerkraumMedia\ThueCat\Domain\Repository\Backend\OrganisationRepository;
use WerkraumMedia\ThueCat\Domain\Repository\Backend\TownRepository;
class TouristAttraction implements Converter
{
/**
* @var ResolveForeignReference
*/
private $resolveForeignReference;
/**
* @var LanguageHandling
*/
private $languageHandling;
/**
* @var OrganisationRepository
*/
private $organisationRepository;
/**
* @var TownRepository
*/
private $townRepository;
public function __construct(
ResolveForeignReference $resolveForeignReference,
LanguageHandling $languageHandling,
OrganisationRepository $organisationRepository,
TownRepository $townRepository
) {
$this->resolveForeignReference = $resolveForeignReference;
$this->languageHandling = $languageHandling;
$this->organisationRepository = $organisationRepository;
$this->townRepository = $townRepository;
}
public function canConvert(MapsToType $entity): bool
{
return $entity instanceof TouristAttractionEntity;
}
public function convert(
MapsToType $entity,
ImportConfiguration $configuration,
string $language
): ?Entity {
if (!$entity instanceof TouristAttractionEntity) {
throw new \InvalidArgumentException('Did not get entity of expected type.', 1628243431);
}
if ($entity->hasName() === false) {
return null;
}
$manager = null;
if ($entity->getManagedBy() instanceof ForeignReference) {
$manager = $this->organisationRepository->findOneByRemoteId(
$entity->getManagedBy()->getId()
);
}
$town = $this->townRepository->findOneByEntity($entity);
return new GenericEntity(
$configuration->getStoragePid(),
'tx_thuecat_tourist_attraction',
$this->languageHandling->getLanguageUidForString(
$configuration->getStoragePid(),
$language
),
$entity->getId(),
[
'title' => $entity->getName(),
'description' => $entity->getDescription(),
'managed_by' => $manager ? $manager->getUid() : 0,
'town' => $town ? $town->getUid() : 0,
'media' => $this->getMedia($entity, $language),
'opening_hours' => $this->getOpeningHours($entity),
'address' => $this->getAddress($entity),
'offers' => $this->getOffers($entity),
]
);
}
private function getMedia(
TouristAttractionEntity $entity,
string $language
): string {
$data = [];
if ($entity->getPhoto() instanceof ForeignReference) {
$photo = $this->resolveForeignReference->resolve(
$entity->getPhoto(),
$language
);
if ($photo instanceof MediaObject) {
$data[] = $this->getSingleMedia($photo, true);
}
}
foreach ($entity->getImages() as $image) {
$image = $this->resolveForeignReference->resolve(
$image,
$language
);
if ($image instanceof MediaObject) {
$data[] = $this->getSingleMedia($image, false);
}
}
return json_encode($data) ?: '';
}
private function getSingleMedia(
MediaObject $mediaObject,
bool $mainImage
): array {
return [
'mainImage' => $mainImage,
'type' => $mediaObject->getType(),
'title' => $mediaObject->getName(),
'description' => $mediaObject->getDescription(),
'url' => $mediaObject->getUrl(),
'copyrightYear' => $mediaObject->getCopyrightYear(),
'license' => [
'type' => $mediaObject->getLicense(),
'author' => $mediaObject->getLicenseAuthor(),
],
];
}
private function getOpeningHours(TouristAttractionEntity $entity): string
{
$data = [];
foreach ($entity->getOpeningHoursSpecification() as $openingHour) {
$data[] = [
'opens' => $openingHour->getOpens()->format('H:i:s'),
'closes' => $openingHour->getCloses()->format('H:i:s'),
'from' => $openingHour->getValidFrom(),
'through' => $openingHour->getValidThrough(),
'daysOfWeek' => $openingHour->getDaysOfWeek(),
];
}
return json_encode($data) ?: '';
}
private function getAddress(TouristAttractionEntity $entity): string
{
$data = [];
$address = $entity->getAddress();
if ($address !== null) {
$data += [
'street' => $address->getStreetAddress(),
'zip' => $address->getPostalCode(),
'city' => $address->getAddressLocality(),
'email' => $address->getEmail(),
'phone' => $address->getTelephone(),
'fax' => $address->getFaxNumber(),
];
}
$geo = $entity->getGeo();
if ($geo !== null) {
$data += [
'geo' => [
'latitude' => $geo->getLatitude(),
'longitude' => $geo->getLongitude(),
],
];
}
return json_encode($data) ?: '';
}
private function getOffers(TouristAttractionEntity $entity): string
{
$data = [];
foreach ($entity->getOffers() as $offer) {
$data[] = [
'title' => $offer->getName(),
'description' => $offer->getDescription(),
'prices' => array_map([$this, 'getPrice'], $offer->getPrices()),
];
}
return json_encode($data) ?: '';
}
private function getPrice(PriceSpecification $priceSpecification): array
{
return [
'title' => $priceSpecification->getName(),
'description' => $priceSpecification->getDescription(),
'price' => $priceSpecification->getPrice(),
'currency' => $priceSpecification->getCurrency(),
'rule' => $priceSpecification->getCalculationRule(),
];
}
}

View file

@ -21,12 +21,12 @@ declare(strict_types=1);
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Converter;
namespace WerkraumMedia\ThueCat\Domain\Import\Typo3Converter;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use WerkraumMedia\ThueCat\Domain\Import\Importer\LanguageHandling;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser;
use WerkraumMedia\ThueCat\Domain\Import\Model\EntityCollection;
use WerkraumMedia\ThueCat\Domain\Import\Entity\MapsToType;
use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\ForeignReference;
use WerkraumMedia\ThueCat\Domain\Import\Entity\TouristInformation as TouristInformationEntity;
use WerkraumMedia\ThueCat\Domain\Import\Model\Entity;
use WerkraumMedia\ThueCat\Domain\Import\Model\GenericEntity;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration;
use WerkraumMedia\ThueCat\Domain\Repository\Backend\OrganisationRepository;
@ -34,16 +34,6 @@ use WerkraumMedia\ThueCat\Domain\Repository\Backend\TownRepository;
class TouristInformation implements Converter
{
/**
* @var Parser
*/
private $parser;
/**
* @var LanguageHandling
*/
private $language;
/**
* @var OrganisationRepository
*/
@ -55,48 +45,51 @@ class TouristInformation implements Converter
private $townRepository;
public function __construct(
Parser $parser,
LanguageHandling $language,
OrganisationRepository $organisationRepository,
TownRepository $townRepository
) {
$this->parser = $parser;
$this->language = $language;
$this->organisationRepository = $organisationRepository;
$this->townRepository = $townRepository;
}
public function convert(array $jsonLD, ImportConfiguration $configuration): EntityCollection
public function canConvert(MapsToType $entity): bool
{
$language = $this->language->getDefaultLanguage($configuration->getStoragePid());
$manager = $this->organisationRepository->findOneByRemoteId(
$this->parser->getManagerId($jsonLD)
);
$town = $this->townRepository->findOneByRemoteIds(
$this->parser->getContainedInPlaceIds($jsonLD)
);
return $entity instanceof TouristInformationEntity;
}
$entity = GeneralUtility::makeInstance(
GenericEntity::class,
public function convert(
MapsToType $entity,
ImportConfiguration $configuration,
string $language
): ?Entity {
if (!$entity instanceof TouristInformationEntity) {
throw new \InvalidArgumentException('Did not get entity of expected type.', 1628243431);
}
if ($entity->hasName() === false) {
return null;
}
$manager = null;
if ($entity->getManagedBy() instanceof ForeignReference) {
$manager = $this->organisationRepository->findOneByRemoteId(
$entity->getManagedBy()->getId()
);
}
$town = $this->townRepository->findOneByEntity($entity);
return new GenericEntity(
$configuration->getStoragePid(),
'tx_thuecat_tourist_information',
0,
$this->parser->getId($jsonLD),
$entity->getId(),
[
'title' => $this->parser->getTitle($jsonLD, $language),
'description' => $this->parser->getDescription($jsonLD, $language),
'title' => $entity->getName(),
'description' => $entity->getDescription(),
'managed_by' => $manager ? $manager->getUid() : 0,
'town' => $town ? $town->getUid() : 0,
]
);
$entities = GeneralUtility::makeInstance(EntityCollection::class);
$entities->add($entity);
return $entities;
}
public function canConvert(array $type): bool
{
return array_search('thuecat:TouristInformation', $type) !== false;
}
}

View file

@ -21,70 +21,64 @@ declare(strict_types=1);
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Domain\Import\Converter;
namespace WerkraumMedia\ThueCat\Domain\Import\Typo3Converter;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use WerkraumMedia\ThueCat\Domain\Import\Importer\LanguageHandling;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser;
use WerkraumMedia\ThueCat\Domain\Import\Model\EntityCollection;
use WerkraumMedia\ThueCat\Domain\Import\Entity\MapsToType;
use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\ForeignReference;
use WerkraumMedia\ThueCat\Domain\Import\Entity\Town as TownEntity;
use WerkraumMedia\ThueCat\Domain\Import\Model\Entity;
use WerkraumMedia\ThueCat\Domain\Import\Model\GenericEntity;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration;
use WerkraumMedia\ThueCat\Domain\Repository\Backend\OrganisationRepository;
class Town implements Converter
{
/**
* @var Parser
*/
private $parser;
/**
* @var LanguageHandling
*/
private $language;
/**
* @var OrganisationRepository
*/
private $organisationRepository;
public function __construct(
Parser $parser,
LanguageHandling $language,
OrganisationRepository $organisationRepository
) {
$this->parser = $parser;
$this->language = $language;
$this->organisationRepository = $organisationRepository;
}
public function convert(array $jsonLD, ImportConfiguration $configuration): EntityCollection
public function canConvert(MapsToType $entity): bool
{
$language = $this->language->getDefaultLanguage($configuration->getStoragePid());
$manager = $this->organisationRepository->findOneByRemoteId(
$this->parser->getManagerId($jsonLD)
);
return $entity instanceof TownEntity;
}
$entity = GeneralUtility::makeInstance(
GenericEntity::class,
public function convert(
MapsToType $entity,
ImportConfiguration $configuration,
string $language
): ?Entity {
if (!$entity instanceof TownEntity) {
throw new \InvalidArgumentException('Did not get entity of expected type.', 1628243431);
}
if ($entity->hasName() === false) {
return null;
}
$manager = null;
if ($entity->getManagedBy() instanceof ForeignReference) {
$manager = $this->organisationRepository->findOneByRemoteId(
$entity->getManagedBy()->getId()
);
}
return new GenericEntity(
$configuration->getStoragePid(),
'tx_thuecat_town',
0,
$this->parser->getId($jsonLD),
$entity->getId(),
[
'title' => $this->parser->getTitle($jsonLD, $language),
'description' => $this->parser->getDescription($jsonLD, $language),
'title' => $entity->getName(),
'description' => $entity->getDescription(),
'managed_by' => $manager ? $manager->getUid() : 0,
]
);
$entities = GeneralUtility::makeInstance(EntityCollection::class);
$entities->add($entity);
return $entities;
}
public function canConvert(array $type): bool
{
return array_search('thuecat:Town', $type) !== false;
}
}

View file

@ -26,11 +26,10 @@ namespace WerkraumMedia\ThueCat\Domain\Repository\Backend;
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
use TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings;
use TYPO3\CMS\Extbase\Persistence\Repository;
use WerkraumMedia\ThueCat\Domain\Import\Entity\Place;
use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\ForeignReference;
use WerkraumMedia\ThueCat\Domain\Model\Backend\Town;
/**
* @method Town|null findOneByRemoteIds(string[] $remoteIds)
*/
class TownRepository extends Repository
{
public function __construct(
@ -44,8 +43,12 @@ class TownRepository extends Repository
$this->setDefaultQuerySettings($querySettings);
}
public function findOneByRemoteIds(array $remoteIds): ?Town
public function findOneByEntity(Place $entity): ?Town
{
$remoteIds = array_map(function (ForeignReference $reference) {
return $reference->getId();
}, $entity->getContainedInPlaces());
if ($remoteIds === []) {
return null;
}

View file

@ -6,7 +6,8 @@ namespace WerkraumMedia\ThueCat;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use WerkraumMedia\ThueCat\Domain\Import\Converter\Converter;
use WerkraumMedia\ThueCat\Domain\Import\Entity\MapsToType;
use WerkraumMedia\ThueCat\Domain\Import\Typo3Converter\Converter;
use WerkraumMedia\ThueCat\Domain\Import\UrlProvider\UrlProvider;
return function (ContainerConfigurator $container, ContainerBuilder $containerBuilder) {
@ -15,4 +16,7 @@ return function (ContainerConfigurator $container, ContainerBuilder $containerBu
$containerBuilder->registerForAutoconfiguration(Converter::class)->addTag(DependencyInjection\ConverterPass::TAG);
$containerBuilder->addCompilerPass(new DependencyInjection\ConverterPass());
$containerBuilder->registerForAutoconfiguration(MapsToType::class)->addTag(DependencyInjection\EntityPass::TAG);
$containerBuilder->addCompilerPass(new DependencyInjection\EntityPass());
};

View file

@ -1,10 +1,10 @@
"tx_thuecat_tourist_attraction",,,,,,,,,,,,,,
,"uid","pid","sys_language_uid","l18n_parent","l10n_source","l10n_state","remote_id","title","managed_by","town","address","offers","media","opening_hours"
,1,10,0,0,0,"\NULL","https://thuecat.org/resources/835224016581-dara","Dom St. Marien",1,1,"{""street"":""Domstufen 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""dominformation@domberg-erfurt.de"",""phone"":""+49 361 6461265"",""fax"":"""",""geo"":{""latitude"":50.975955358589545,""longitude"":11.023667024961856}}","[]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Dom und Severikirche-beleuchtet.jpg"",""description"":"""",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159216\/Preview-1280x0\/image"",""copyrightYear"":2016,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Dom-und-Severikirche.jpg"",""description"":""Sicht auf Dom St. Marien, St. Severikirche sowie die davor liegenden Klostergeb\u00e4ude und einem Ausschnitt des Biergartens umgeben von einem d\u00e4mmerungsverf\u00e4rten Himmel"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159186\/Preview-1280x0\/image"",""copyrightYear"":2020,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Dom und Severikirche-beleuchtet.jpg"",""description"":"""",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159216\/Preview-1280x0\/image"",""copyrightYear"":2016,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}}]","[{""opens"":""09:30:00"",""closes"":""18:00:00"",""from"":{""date"":""2021-05-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2021-10-31 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Friday"",""Monday"",""Saturday"",""Thursday"",""Tuesday"",""Wednesday""]},{""opens"":""13:00:00"",""closes"":""18:00:00"",""from"":{""date"":""2021-05-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2021-10-31 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Sunday""]},{""opens"":""09:30:00"",""closes"":""17:00:00"",""from"":{""date"":""2021-11-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2022-04-30 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Friday"",""Monday"",""Saturday"",""Thursday"",""Tuesday"",""Wednesday""]},{""opens"":""13:00:00"",""closes"":""17:00:00"",""from"":{""date"":""2021-11-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2022-04-30 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Sunday""]}]"
,2,10,1,1,1,"\NULL","https://thuecat.org/resources/835224016581-dara","Cathedral of St. Mary",1,1,"{""street"":""Domstufen 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""dominformation@domberg-erfurt.de"",""phone"":""+49 361 6461265"",""fax"":"""",""geo"":{""latitude"":50.975955358589545,""longitude"":11.023667024961856}}","[]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Dom und Severikirche-beleuchtet.jpg"",""description"":"""",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159216\/Preview-1280x0\/image"",""copyrightYear"":2016,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Dom-und-Severikirche.jpg"",""description"":""Sicht auf Dom St. Marien, St. Severikirche sowie die davor liegenden Klostergeb\u00e4ude und einem Ausschnitt des Biergartens umgeben von einem d\u00e4mmerungsverf\u00e4rten Himmel"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159186\/Preview-1280x0\/image"",""copyrightYear"":2020,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Dom und Severikirche-beleuchtet.jpg"",""description"":"""",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159216\/Preview-1280x0\/image"",""copyrightYear"":2016,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}}]","[{""opens"":""09:30:00"",""closes"":""18:00:00"",""from"":{""date"":""2021-05-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2021-10-31 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Friday"",""Monday"",""Saturday"",""Thursday"",""Tuesday"",""Wednesday""]},{""opens"":""13:00:00"",""closes"":""18:00:00"",""from"":{""date"":""2021-05-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2021-10-31 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Sunday""]},{""opens"":""09:30:00"",""closes"":""17:00:00"",""from"":{""date"":""2021-11-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2022-04-30 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Friday"",""Monday"",""Saturday"",""Thursday"",""Tuesday"",""Wednesday""]},{""opens"":""13:00:00"",""closes"":""17:00:00"",""from"":{""date"":""2021-11-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2022-04-30 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Sunday""]}]"
,3,10,0,0,0,"\NULL","https://thuecat.org/resources/165868194223-zmqf","Alte Synagoge",1,1,"{""street"":""Waagegasse 8"",""zip"":""99084"",""city"":""Erfurt"",""email"":""altesynagoge@erfurt.de"",""phone"":""+49 361 6551520"",""fax"":""+49 361 6551669"",""geo"":{""latitude"":50.978765,""longitude"":11.029133}}","[{""title"":""F\u00fchrungen"",""description"":""Immer samstags, um 11:15 Uhr findet eine \u00f6ffentliche F\u00fchrung durch das Museum statt. Dauer etwa 90 Minuten"",""prices"":[{""title"":""Erwachsene"",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":""Erm\u00e4\u00dfigt"",""description"":""als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt"",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""}]},{""title"":""Eintritt"",""description"":""Schulklassen und Kitagruppen im Rahmen des Unterrichts: Eintritt frei\nAn jedem ersten Dienstag im Monat: Eintritt frei"",""prices"":[{""title"":""Erm\u00e4\u00dfigt"",""description"":""als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt"",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":""Familienkarte"",""description"":"""",""price"":17,""currency"":""EUR"",""rule"":""PerGroup""},{""title"":""ErfurtCard"",""description"":"""",""price"":14.9,""currency"":""EUR"",""rule"":""PerPackage""},{""title"":""Erwachsene"",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""}]}]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Alte Synagoge"",""description"":""Frontaler Blick auf die Hausfront\/Hausfassade im Innenhof mit Zugang \u00fcber die Waagegasse"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5099196\/Preview-1280x0\/image"",""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 \u00fcber 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""}}]","[{""opens"":""10:00:00"",""closes"":""18:00:00"",""from"":{""date"":""2021-03-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2021-12-31 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Friday"",""Saturday"",""Sunday"",""Thursday"",""Tuesday"",""Wednesday""]}]"
,4,10,1,3,3,"\NULL","https://thuecat.org/resources/165868194223-zmqf","Old Synagogue",1,1,"{""street"":""Waagegasse 8"",""zip"":""99084"",""city"":""Erfurt"",""email"":""altesynagoge@erfurt.de"",""phone"":""+49 361 6551520"",""fax"":""+49 361 6551669"",""geo"":{""latitude"":50.978765,""longitude"":11.029133}}","[{""title"":""F\u00fchrungen"",""description"":""Immer samstags, um 11:15 Uhr findet eine \u00f6ffentliche F\u00fchrung durch das Museum statt. Dauer etwa 90 Minuten"",""prices"":[{""title"":""Erwachsene"",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":""Erm\u00e4\u00dfigt"",""description"":""als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt"",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""}]},{""title"":""Eintritt"",""description"":""Schulklassen und Kitagruppen im Rahmen des Unterrichts: Eintritt frei\nAn jedem ersten Dienstag im Monat: Eintritt frei"",""prices"":[{""title"":""Erm\u00e4\u00dfigt"",""description"":""als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt"",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":""Familienkarte"",""description"":"""",""price"":17,""currency"":""EUR"",""rule"":""PerGroup""},{""title"":""ErfurtCard"",""description"":"""",""price"":14.9,""currency"":""EUR"",""rule"":""PerPackage""},{""title"":""Erwachsene"",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""}]}]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Alte Synagoge"",""description"":""Frontaler Blick auf die Hausfront\/Hausfassade im Innenhof mit Zugang \u00fcber die Waagegasse"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5099196\/Preview-1280x0\/image"",""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 \u00fcber 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""}}]","[{""opens"":""10:00:00"",""closes"":""18:00:00"",""from"":{""date"":""2021-03-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2021-12-31 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Friday"",""Saturday"",""Sunday"",""Thursday"",""Tuesday"",""Wednesday""]}]"
,5,10,2,3,3,"\NULL","https://thuecat.org/resources/165868194223-zmqf","La vieille synagogue",1,1,"{""street"":""Waagegasse 8"",""zip"":""99084"",""city"":""Erfurt"",""email"":""altesynagoge@erfurt.de"",""phone"":""+49 361 6551520"",""fax"":""+49 361 6551669"",""geo"":{""latitude"":50.978765,""longitude"":11.029133}}","[{""title"":""F\u00fchrungen"",""description"":""Immer samstags, um 11:15 Uhr findet eine \u00f6ffentliche F\u00fchrung durch das Museum statt. Dauer etwa 90 Minuten"",""prices"":[{""title"":""Erwachsene"",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":""Erm\u00e4\u00dfigt"",""description"":""als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt"",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""}]},{""title"":""Eintritt"",""description"":""Schulklassen und Kitagruppen im Rahmen des Unterrichts: Eintritt frei\nAn jedem ersten Dienstag im Monat: Eintritt frei"",""prices"":[{""title"":""Erm\u00e4\u00dfigt"",""description"":""als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt"",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":""Familienkarte"",""description"":"""",""price"":17,""currency"":""EUR"",""rule"":""PerGroup""},{""title"":""ErfurtCard"",""description"":"""",""price"":14.9,""currency"":""EUR"",""rule"":""PerPackage""},{""title"":""Erwachsene"",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""}]}]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Alte Synagoge"",""description"":""Frontaler Blick auf die Hausfront\/Hausfassade im Innenhof mit Zugang \u00fcber die Waagegasse"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5099196\/Preview-1280x0\/image"",""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 \u00fcber 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""}}]","[{""opens"":""10:00:00"",""closes"":""18:00:00"",""from"":{""date"":""2021-03-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2021-12-31 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Friday"",""Saturday"",""Sunday"",""Thursday"",""Tuesday"",""Wednesday""]}]"
,1,10,0,0,0,"\NULL","https://thuecat.org/resources/835224016581-dara","Dom St. Marien",1,1,"{""street"":""Domstufen 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""dominformation@domberg-erfurt.de"",""phone"":""+49 361 6461265"",""fax"":"""",""geo"":{""latitude"":50.975955358589545,""longitude"":11.023667024961856}}","[]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Dom und Severikirche-beleuchtet.jpg"",""description"":"""",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159216\/Preview-1280x0\/image"",""copyrightYear"":2016,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Dom-und-Severikirche.jpg"",""description"":""Sicht auf Dom St. Marien, St. Severikirche sowie die davor liegenden Klostergeb\u00e4ude und einem Ausschnitt des Biergartens umgeben von einem d\u00e4mmerungsverf\u00e4rten Himmel"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159186\/Preview-1280x0\/image"",""copyrightYear"":2020,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Dom und Severikirche-beleuchtet.jpg"",""description"":"""",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159216\/Preview-1280x0\/image"",""copyrightYear"":2016,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}}]","[{""opens"":""09:30:00"",""closes"":""18:00:00"",""from"":{""date"":""2021-05-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2021-10-31 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Saturday"",""Friday"",""Thursday"",""Tuesday"",""Monday"",""Wednesday""]},{""opens"":""13:00:00"",""closes"":""18:00:00"",""from"":{""date"":""2021-05-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2021-10-31 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Sunday""]},{""opens"":""09:30:00"",""closes"":""17:00:00"",""from"":{""date"":""2021-11-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2022-04-30 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Saturday"",""Friday"",""Thursday"",""Tuesday"",""Monday"",""Wednesday""]},{""opens"":""13:00:00"",""closes"":""17:00:00"",""from"":{""date"":""2021-11-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2022-04-30 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Sunday""]}]"
,2,10,1,1,1,"\NULL","https://thuecat.org/resources/835224016581-dara","Cathedral of St. Mary",1,1,"{""street"":""Domstufen 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""dominformation@domberg-erfurt.de"",""phone"":""+49 361 6461265"",""fax"":"""",""geo"":{""latitude"":50.975955358589545,""longitude"":11.023667024961856}}","[]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Dom und Severikirche-beleuchtet.jpg"",""description"":"""",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159216\/Preview-1280x0\/image"",""copyrightYear"":2016,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Dom-und-Severikirche.jpg"",""description"":""Sicht auf Dom St. Marien, St. Severikirche sowie die davor liegenden Klostergeb\u00e4ude und einem Ausschnitt des Biergartens umgeben von einem d\u00e4mmerungsverf\u00e4rten Himmel"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159186\/Preview-1280x0\/image"",""copyrightYear"":2020,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Dom und Severikirche-beleuchtet.jpg"",""description"":"""",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159216\/Preview-1280x0\/image"",""copyrightYear"":2016,""license"":{""type"":""https:\/\/creativecommons.org\/licenses\/by\/4.0\/"",""author"":""""}}]","[{""opens"":""09:30:00"",""closes"":""18:00:00"",""from"":{""date"":""2021-05-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2021-10-31 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Saturday"",""Friday"",""Thursday"",""Tuesday"",""Monday"",""Wednesday""]},{""opens"":""13:00:00"",""closes"":""18:00:00"",""from"":{""date"":""2021-05-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2021-10-31 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Sunday""]},{""opens"":""09:30:00"",""closes"":""17:00:00"",""from"":{""date"":""2021-11-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2022-04-30 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Saturday"",""Friday"",""Thursday"",""Tuesday"",""Monday"",""Wednesday""]},{""opens"":""13:00:00"",""closes"":""17:00:00"",""from"":{""date"":""2021-11-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2022-04-30 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Sunday""]}]"
,3,10,0,0,0,"\NULL","https://thuecat.org/resources/165868194223-zmqf","Alte Synagoge",1,1,"{""street"":""Waagegasse 8"",""zip"":""99084"",""city"":""Erfurt"",""email"":""altesynagoge@erfurt.de"",""phone"":""+49 361 6551520"",""fax"":""+49 361 6551669"",""geo"":{""latitude"":50.978765,""longitude"":11.029133}}","[{""title"":""F\u00fchrungen"",""description"":""Immer samstags, um 11:15 Uhr findet eine \u00f6ffentliche F\u00fchrung durch das Museum statt. Dauer etwa 90 Minuten"",""prices"":[{""title"":""Erwachsene"",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":""Erm\u00e4\u00dfigt"",""description"":""als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt"",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""}]},{""title"":""Eintritt"",""description"":""Schulklassen und Kitagruppen im Rahmen des Unterrichts: Eintritt frei\nAn jedem ersten Dienstag im Monat: Eintritt frei"",""prices"":[{""title"":""Erm\u00e4\u00dfigt"",""description"":""als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt"",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":""Familienkarte"",""description"":"""",""price"":17,""currency"":""EUR"",""rule"":""PerGroup""},{""title"":""ErfurtCard"",""description"":"""",""price"":14.9,""currency"":""EUR"",""rule"":""PerPackage""},{""title"":""Erwachsene"",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""}]}]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Alte Synagoge"",""description"":""Frontaler Blick auf die Hausfront\/Hausfassade im Innenhof mit Zugang \u00fcber die Waagegasse"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5099196\/Preview-1280x0\/image"",""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 \u00fcber 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""}}]","[{""opens"":""10:00:00"",""closes"":""18:00:00"",""from"":{""date"":""2021-03-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2021-12-31 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Saturday"",""Sunday"",""Friday"",""Thursday"",""Tuesday"",""Wednesday""]}]"
,4,10,1,3,3,"\NULL","https://thuecat.org/resources/165868194223-zmqf","Old Synagogue",1,1,"{""street"":""Waagegasse 8"",""zip"":""99084"",""city"":""Erfurt"",""email"":""altesynagoge@erfurt.de"",""phone"":""+49 361 6551520"",""fax"":""+49 361 6551669"",""geo"":{""latitude"":50.978765,""longitude"":11.029133}}","[{""title"":""F\u00fchrungen"",""description"":""Immer samstags, um 11:15 Uhr findet eine \u00f6ffentliche F\u00fchrung durch das Museum statt. Dauer etwa 90 Minuten"",""prices"":[{""title"":""Erwachsene"",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":""Erm\u00e4\u00dfigt"",""description"":""als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt"",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""}]},{""title"":""Eintritt"",""description"":""Schulklassen und Kitagruppen im Rahmen des Unterrichts: Eintritt frei\nAn jedem ersten Dienstag im Monat: Eintritt frei"",""prices"":[{""title"":""Erm\u00e4\u00dfigt"",""description"":""als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt"",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":""Familienkarte"",""description"":"""",""price"":17,""currency"":""EUR"",""rule"":""PerGroup""},{""title"":""ErfurtCard"",""description"":"""",""price"":14.9,""currency"":""EUR"",""rule"":""PerPackage""},{""title"":""Erwachsene"",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""}]}]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Alte Synagoge"",""description"":""Frontaler Blick auf die Hausfront\/Hausfassade im Innenhof mit Zugang \u00fcber die Waagegasse"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5099196\/Preview-1280x0\/image"",""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 \u00fcber 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""}}]","[{""opens"":""10:00:00"",""closes"":""18:00:00"",""from"":{""date"":""2021-03-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2021-12-31 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Saturday"",""Sunday"",""Friday"",""Thursday"",""Tuesday"",""Wednesday""]}]"
,5,10,2,3,3,"\NULL","https://thuecat.org/resources/165868194223-zmqf","La vieille synagogue",1,1,"{""street"":""Waagegasse 8"",""zip"":""99084"",""city"":""Erfurt"",""email"":""altesynagoge@erfurt.de"",""phone"":""+49 361 6551520"",""fax"":""+49 361 6551669"",""geo"":{""latitude"":50.978765,""longitude"":11.029133}}","[{""title"":""F\u00fchrungen"",""description"":""Immer samstags, um 11:15 Uhr findet eine \u00f6ffentliche F\u00fchrung durch das Museum statt. Dauer etwa 90 Minuten"",""prices"":[{""title"":""Erwachsene"",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":""Erm\u00e4\u00dfigt"",""description"":""als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt"",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""}]},{""title"":""Eintritt"",""description"":""Schulklassen und Kitagruppen im Rahmen des Unterrichts: Eintritt frei\nAn jedem ersten Dienstag im Monat: Eintritt frei"",""prices"":[{""title"":""Erm\u00e4\u00dfigt"",""description"":""als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt"",""price"":5,""currency"":""EUR"",""rule"":""PerPerson""},{""title"":""Familienkarte"",""description"":"""",""price"":17,""currency"":""EUR"",""rule"":""PerGroup""},{""title"":""ErfurtCard"",""description"":"""",""price"":14.9,""currency"":""EUR"",""rule"":""PerPackage""},{""title"":""Erwachsene"",""description"":"""",""price"":8,""currency"":""EUR"",""rule"":""PerPerson""}]}]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Alte Synagoge"",""description"":""Frontaler Blick auf die Hausfront\/Hausfassade im Innenhof mit Zugang \u00fcber die Waagegasse"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5099196\/Preview-1280x0\/image"",""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 \u00fcber 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""}}]","[{""opens"":""10:00:00"",""closes"":""18:00:00"",""from"":{""date"":""2021-03-01 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""through"":{""date"":""2021-12-31 00:00:00.000000"",""timezone_type"":3,""timezone"":""UTC""},""daysOfWeek"":[""Saturday"",""Sunday"",""Friday"",""Thursday"",""Tuesday"",""Wednesday""]}]"
,6,10,0,0,0,"\NULL","https://thuecat.org/resources/215230952334-yyno","Krämerbrücke",1,1,"{""street"":""Benediktsplatz 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""service@erfurt-tourismus.de"",""phone"":""+49 361 66 400"",""fax"":"""",""geo"":{""latitude"":50.978772,""longitude"":11.031622}}","[]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Kraemerbruecke-11.jpg"",""description"":""Kr\u00e4merbr\u00fccke in Erfurt"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134362\/Preview-1280x0\/image"",""copyrightYear"":2019,""license"":{""type"":""https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de"",""author"":""https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Kraemerbruecke.jpg"",""description"":""Kr\u00e4merbr\u00fccke in Erfurt"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134288\/Preview-1280x0\/image"",""copyrightYear"":2019,""license"":{""type"":""https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de"",""author"":""https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Kraemerbruecke-11.jpg"",""description"":""Kr\u00e4merbr\u00fccke in Erfurt"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134362\/Preview-1280x0\/image"",""copyrightYear"":2019,""license"":{""type"":""https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de"",""author"":""https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Kraemerbruecke-13.jpg"",""description"":""Ansicht der Kr\u00e4merbr\u00fccke, Erfurt"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/652340\/Preview-1280x0\/image"",""copyrightYear"":2019,""license"":{""type"":""https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de"",""author"":""https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion""}}]","[]"
,7,10,1,6,6,"\NULL","https://thuecat.org/resources/215230952334-yyno","Merchants' Bridge",1,1,"{""street"":""Benediktsplatz 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""service@erfurt-tourismus.de"",""phone"":""+49 361 66 400"",""fax"":"""",""geo"":{""latitude"":50.978772,""longitude"":11.031622}}","[]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Kraemerbruecke-11.jpg"",""description"":""Kr\u00e4merbr\u00fccke in Erfurt"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134362\/Preview-1280x0\/image"",""copyrightYear"":2019,""license"":{""type"":""https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de"",""author"":""https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Kraemerbruecke.jpg"",""description"":""Kr\u00e4merbr\u00fccke in Erfurt"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134288\/Preview-1280x0\/image"",""copyrightYear"":2019,""license"":{""type"":""https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de"",""author"":""https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Kraemerbruecke-11.jpg"",""description"":""Kr\u00e4merbr\u00fccke in Erfurt"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134362\/Preview-1280x0\/image"",""copyrightYear"":2019,""license"":{""type"":""https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de"",""author"":""https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Kraemerbruecke-13.jpg"",""description"":""Ansicht der Kr\u00e4merbr\u00fccke, Erfurt"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/652340\/Preview-1280x0\/image"",""copyrightYear"":2019,""license"":{""type"":""https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de"",""author"":""https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion""}}]","[]"
,8,10,2,6,6,"\NULL","https://thuecat.org/resources/215230952334-yyno","Pont de l'épicier",1,1,"{""street"":""Benediktsplatz 1"",""zip"":""99084"",""city"":""Erfurt"",""email"":""service@erfurt-tourismus.de"",""phone"":""+49 361 66 400"",""fax"":"""",""geo"":{""latitude"":50.978772,""longitude"":11.031622}}","[]","[{""mainImage"":true,""type"":""image"",""title"":""Erfurt-Kraemerbruecke-11.jpg"",""description"":""Kr\u00e4merbr\u00fccke in Erfurt"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134362\/Preview-1280x0\/image"",""copyrightYear"":2019,""license"":{""type"":""https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de"",""author"":""https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Kraemerbruecke.jpg"",""description"":""Kr\u00e4merbr\u00fccke in Erfurt"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134288\/Preview-1280x0\/image"",""copyrightYear"":2019,""license"":{""type"":""https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de"",""author"":""https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Kraemerbruecke-11.jpg"",""description"":""Kr\u00e4merbr\u00fccke in Erfurt"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134362\/Preview-1280x0\/image"",""copyrightYear"":2019,""license"":{""type"":""https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de"",""author"":""https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion""}},{""mainImage"":false,""type"":""image"",""title"":""Erfurt-Kraemerbruecke-13.jpg"",""description"":""Ansicht der Kr\u00e4merbr\u00fccke, Erfurt"",""url"":""https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/652340\/Preview-1280x0\/image"",""copyrightYear"":2019,""license"":{""type"":""https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de"",""author"":""https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion""}}]","[]"

1 tx_thuecat_tourist_attraction
2 uid pid sys_language_uid l18n_parent l10n_source l10n_state remote_id title managed_by town address offers media opening_hours
3 1 10 0 0 0 \NULL https://thuecat.org/resources/835224016581-dara Dom St. Marien 1 1 {"street":"Domstufen 1","zip":"99084","city":"Erfurt","email":"dominformation@domberg-erfurt.de","phone":"+49 361 6461265","fax":"","geo":{"latitude":50.975955358589545,"longitude":11.023667024961856}} [] [{"mainImage":true,"type":"image","title":"Erfurt-Dom und Severikirche-beleuchtet.jpg","description":"","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159216\/Preview-1280x0\/image","copyrightYear":2016,"license":{"type":"https:\/\/creativecommons.org\/licenses\/by\/4.0\/","author":""}},{"mainImage":false,"type":"image","title":"Erfurt-Dom-und-Severikirche.jpg","description":"Sicht auf Dom St. Marien, St. Severikirche sowie die davor liegenden Klostergeb\u00e4ude und einem Ausschnitt des Biergartens umgeben von einem d\u00e4mmerungsverf\u00e4rten Himmel","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159186\/Preview-1280x0\/image","copyrightYear":2020,"license":{"type":"https:\/\/creativecommons.org\/licenses\/by\/4.0\/","author":""}},{"mainImage":false,"type":"image","title":"Erfurt-Dom und Severikirche-beleuchtet.jpg","description":"","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159216\/Preview-1280x0\/image","copyrightYear":2016,"license":{"type":"https:\/\/creativecommons.org\/licenses\/by\/4.0\/","author":""}}] [{"opens":"09:30:00","closes":"18:00:00","from":{"date":"2021-05-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2021-10-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Friday","Monday","Saturday","Thursday","Tuesday","Wednesday"]},{"opens":"13:00:00","closes":"18:00:00","from":{"date":"2021-05-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2021-10-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Sunday"]},{"opens":"09:30:00","closes":"17:00:00","from":{"date":"2021-11-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2022-04-30 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Friday","Monday","Saturday","Thursday","Tuesday","Wednesday"]},{"opens":"13:00:00","closes":"17:00:00","from":{"date":"2021-11-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2022-04-30 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Sunday"]}] [{"opens":"09:30:00","closes":"18:00:00","from":{"date":"2021-05-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2021-10-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Saturday","Friday","Thursday","Tuesday","Monday","Wednesday"]},{"opens":"13:00:00","closes":"18:00:00","from":{"date":"2021-05-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2021-10-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Sunday"]},{"opens":"09:30:00","closes":"17:00:00","from":{"date":"2021-11-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2022-04-30 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Saturday","Friday","Thursday","Tuesday","Monday","Wednesday"]},{"opens":"13:00:00","closes":"17:00:00","from":{"date":"2021-11-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2022-04-30 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Sunday"]}]
4 2 10 1 1 1 \NULL https://thuecat.org/resources/835224016581-dara Cathedral of St. Mary 1 1 {"street":"Domstufen 1","zip":"99084","city":"Erfurt","email":"dominformation@domberg-erfurt.de","phone":"+49 361 6461265","fax":"","geo":{"latitude":50.975955358589545,"longitude":11.023667024961856}} [] [{"mainImage":true,"type":"image","title":"Erfurt-Dom und Severikirche-beleuchtet.jpg","description":"","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159216\/Preview-1280x0\/image","copyrightYear":2016,"license":{"type":"https:\/\/creativecommons.org\/licenses\/by\/4.0\/","author":""}},{"mainImage":false,"type":"image","title":"Erfurt-Dom-und-Severikirche.jpg","description":"Sicht auf Dom St. Marien, St. Severikirche sowie die davor liegenden Klostergeb\u00e4ude und einem Ausschnitt des Biergartens umgeben von einem d\u00e4mmerungsverf\u00e4rten Himmel","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159186\/Preview-1280x0\/image","copyrightYear":2020,"license":{"type":"https:\/\/creativecommons.org\/licenses\/by\/4.0\/","author":""}},{"mainImage":false,"type":"image","title":"Erfurt-Dom und Severikirche-beleuchtet.jpg","description":"","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5159216\/Preview-1280x0\/image","copyrightYear":2016,"license":{"type":"https:\/\/creativecommons.org\/licenses\/by\/4.0\/","author":""}}] [{"opens":"09:30:00","closes":"18:00:00","from":{"date":"2021-05-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2021-10-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Friday","Monday","Saturday","Thursday","Tuesday","Wednesday"]},{"opens":"13:00:00","closes":"18:00:00","from":{"date":"2021-05-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2021-10-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Sunday"]},{"opens":"09:30:00","closes":"17:00:00","from":{"date":"2021-11-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2022-04-30 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Friday","Monday","Saturday","Thursday","Tuesday","Wednesday"]},{"opens":"13:00:00","closes":"17:00:00","from":{"date":"2021-11-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2022-04-30 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Sunday"]}] [{"opens":"09:30:00","closes":"18:00:00","from":{"date":"2021-05-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2021-10-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Saturday","Friday","Thursday","Tuesday","Monday","Wednesday"]},{"opens":"13:00:00","closes":"18:00:00","from":{"date":"2021-05-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2021-10-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Sunday"]},{"opens":"09:30:00","closes":"17:00:00","from":{"date":"2021-11-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2022-04-30 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Saturday","Friday","Thursday","Tuesday","Monday","Wednesday"]},{"opens":"13:00:00","closes":"17:00:00","from":{"date":"2021-11-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2022-04-30 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Sunday"]}]
5 3 10 0 0 0 \NULL https://thuecat.org/resources/165868194223-zmqf Alte Synagoge 1 1 {"street":"Waagegasse 8","zip":"99084","city":"Erfurt","email":"altesynagoge@erfurt.de","phone":"+49 361 6551520","fax":"+49 361 6551669","geo":{"latitude":50.978765,"longitude":11.029133}} [{"title":"F\u00fchrungen","description":"Immer samstags, um 11:15 Uhr findet eine \u00f6ffentliche F\u00fchrung durch das Museum statt. Dauer etwa 90 Minuten","prices":[{"title":"Erwachsene","description":"","price":8,"currency":"EUR","rule":"PerPerson"},{"title":"Erm\u00e4\u00dfigt","description":"als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt","price":5,"currency":"EUR","rule":"PerPerson"}]},{"title":"Eintritt","description":"Schulklassen und Kitagruppen im Rahmen des Unterrichts: Eintritt frei\nAn jedem ersten Dienstag im Monat: Eintritt frei","prices":[{"title":"Erm\u00e4\u00dfigt","description":"als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt","price":5,"currency":"EUR","rule":"PerPerson"},{"title":"Familienkarte","description":"","price":17,"currency":"EUR","rule":"PerGroup"},{"title":"ErfurtCard","description":"","price":14.9,"currency":"EUR","rule":"PerPackage"},{"title":"Erwachsene","description":"","price":8,"currency":"EUR","rule":"PerPerson"}]}] [{"mainImage":true,"type":"image","title":"Erfurt-Alte Synagoge","description":"Frontaler Blick auf die Hausfront\/Hausfassade im Innenhof mit Zugang \u00fcber die Waagegasse","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5099196\/Preview-1280x0\/image","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 \u00fcber 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"}}] [{"opens":"10:00:00","closes":"18:00:00","from":{"date":"2021-03-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2021-12-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Friday","Saturday","Sunday","Thursday","Tuesday","Wednesday"]}] [{"opens":"10:00:00","closes":"18:00:00","from":{"date":"2021-03-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2021-12-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Saturday","Sunday","Friday","Thursday","Tuesday","Wednesday"]}]
6 4 10 1 3 3 \NULL https://thuecat.org/resources/165868194223-zmqf Old Synagogue 1 1 {"street":"Waagegasse 8","zip":"99084","city":"Erfurt","email":"altesynagoge@erfurt.de","phone":"+49 361 6551520","fax":"+49 361 6551669","geo":{"latitude":50.978765,"longitude":11.029133}} [{"title":"F\u00fchrungen","description":"Immer samstags, um 11:15 Uhr findet eine \u00f6ffentliche F\u00fchrung durch das Museum statt. Dauer etwa 90 Minuten","prices":[{"title":"Erwachsene","description":"","price":8,"currency":"EUR","rule":"PerPerson"},{"title":"Erm\u00e4\u00dfigt","description":"als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt","price":5,"currency":"EUR","rule":"PerPerson"}]},{"title":"Eintritt","description":"Schulklassen und Kitagruppen im Rahmen des Unterrichts: Eintritt frei\nAn jedem ersten Dienstag im Monat: Eintritt frei","prices":[{"title":"Erm\u00e4\u00dfigt","description":"als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt","price":5,"currency":"EUR","rule":"PerPerson"},{"title":"Familienkarte","description":"","price":17,"currency":"EUR","rule":"PerGroup"},{"title":"ErfurtCard","description":"","price":14.9,"currency":"EUR","rule":"PerPackage"},{"title":"Erwachsene","description":"","price":8,"currency":"EUR","rule":"PerPerson"}]}] [{"mainImage":true,"type":"image","title":"Erfurt-Alte Synagoge","description":"Frontaler Blick auf die Hausfront\/Hausfassade im Innenhof mit Zugang \u00fcber die Waagegasse","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5099196\/Preview-1280x0\/image","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 \u00fcber 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"}}] [{"opens":"10:00:00","closes":"18:00:00","from":{"date":"2021-03-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2021-12-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Friday","Saturday","Sunday","Thursday","Tuesday","Wednesday"]}] [{"opens":"10:00:00","closes":"18:00:00","from":{"date":"2021-03-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2021-12-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Saturday","Sunday","Friday","Thursday","Tuesday","Wednesday"]}]
7 5 10 2 3 3 \NULL https://thuecat.org/resources/165868194223-zmqf La vieille synagogue 1 1 {"street":"Waagegasse 8","zip":"99084","city":"Erfurt","email":"altesynagoge@erfurt.de","phone":"+49 361 6551520","fax":"+49 361 6551669","geo":{"latitude":50.978765,"longitude":11.029133}} [{"title":"F\u00fchrungen","description":"Immer samstags, um 11:15 Uhr findet eine \u00f6ffentliche F\u00fchrung durch das Museum statt. Dauer etwa 90 Minuten","prices":[{"title":"Erwachsene","description":"","price":8,"currency":"EUR","rule":"PerPerson"},{"title":"Erm\u00e4\u00dfigt","description":"als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt","price":5,"currency":"EUR","rule":"PerPerson"}]},{"title":"Eintritt","description":"Schulklassen und Kitagruppen im Rahmen des Unterrichts: Eintritt frei\nAn jedem ersten Dienstag im Monat: Eintritt frei","prices":[{"title":"Erm\u00e4\u00dfigt","description":"als erm\u00e4\u00dfigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner\/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt","price":5,"currency":"EUR","rule":"PerPerson"},{"title":"Familienkarte","description":"","price":17,"currency":"EUR","rule":"PerGroup"},{"title":"ErfurtCard","description":"","price":14.9,"currency":"EUR","rule":"PerPackage"},{"title":"Erwachsene","description":"","price":8,"currency":"EUR","rule":"PerPerson"}]}] [{"mainImage":true,"type":"image","title":"Erfurt-Alte Synagoge","description":"Frontaler Blick auf die Hausfront\/Hausfassade im Innenhof mit Zugang \u00fcber die Waagegasse","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/5099196\/Preview-1280x0\/image","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 \u00fcber 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"}}] [{"opens":"10:00:00","closes":"18:00:00","from":{"date":"2021-03-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2021-12-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Friday","Saturday","Sunday","Thursday","Tuesday","Wednesday"]}] [{"opens":"10:00:00","closes":"18:00:00","from":{"date":"2021-03-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"through":{"date":"2021-12-31 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"daysOfWeek":["Saturday","Sunday","Friday","Thursday","Tuesday","Wednesday"]}]
8 6 10 0 0 0 \NULL https://thuecat.org/resources/215230952334-yyno Krämerbrücke 1 1 {"street":"Benediktsplatz 1","zip":"99084","city":"Erfurt","email":"service@erfurt-tourismus.de","phone":"+49 361 66 400","fax":"","geo":{"latitude":50.978772,"longitude":11.031622}} [] [{"mainImage":true,"type":"image","title":"Erfurt-Kraemerbruecke-11.jpg","description":"Kr\u00e4merbr\u00fccke in Erfurt","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134362\/Preview-1280x0\/image","copyrightYear":2019,"license":{"type":"https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de","author":"https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion"}},{"mainImage":false,"type":"image","title":"Erfurt-Kraemerbruecke.jpg","description":"Kr\u00e4merbr\u00fccke in Erfurt","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134288\/Preview-1280x0\/image","copyrightYear":2019,"license":{"type":"https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de","author":"https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion"}},{"mainImage":false,"type":"image","title":"Erfurt-Kraemerbruecke-11.jpg","description":"Kr\u00e4merbr\u00fccke in Erfurt","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134362\/Preview-1280x0\/image","copyrightYear":2019,"license":{"type":"https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de","author":"https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion"}},{"mainImage":false,"type":"image","title":"Erfurt-Kraemerbruecke-13.jpg","description":"Ansicht der Kr\u00e4merbr\u00fccke, Erfurt","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/652340\/Preview-1280x0\/image","copyrightYear":2019,"license":{"type":"https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de","author":"https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion"}}] []
9 7 10 1 6 6 \NULL https://thuecat.org/resources/215230952334-yyno Merchants' Bridge 1 1 {"street":"Benediktsplatz 1","zip":"99084","city":"Erfurt","email":"service@erfurt-tourismus.de","phone":"+49 361 66 400","fax":"","geo":{"latitude":50.978772,"longitude":11.031622}} [] [{"mainImage":true,"type":"image","title":"Erfurt-Kraemerbruecke-11.jpg","description":"Kr\u00e4merbr\u00fccke in Erfurt","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134362\/Preview-1280x0\/image","copyrightYear":2019,"license":{"type":"https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de","author":"https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion"}},{"mainImage":false,"type":"image","title":"Erfurt-Kraemerbruecke.jpg","description":"Kr\u00e4merbr\u00fccke in Erfurt","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134288\/Preview-1280x0\/image","copyrightYear":2019,"license":{"type":"https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de","author":"https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion"}},{"mainImage":false,"type":"image","title":"Erfurt-Kraemerbruecke-11.jpg","description":"Kr\u00e4merbr\u00fccke in Erfurt","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134362\/Preview-1280x0\/image","copyrightYear":2019,"license":{"type":"https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de","author":"https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion"}},{"mainImage":false,"type":"image","title":"Erfurt-Kraemerbruecke-13.jpg","description":"Ansicht der Kr\u00e4merbr\u00fccke, Erfurt","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/652340\/Preview-1280x0\/image","copyrightYear":2019,"license":{"type":"https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de","author":"https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion"}}] []
10 8 10 2 6 6 \NULL https://thuecat.org/resources/215230952334-yyno Pont de l'épicier 1 1 {"street":"Benediktsplatz 1","zip":"99084","city":"Erfurt","email":"service@erfurt-tourismus.de","phone":"+49 361 66 400","fax":"","geo":{"latitude":50.978772,"longitude":11.031622}} [] [{"mainImage":true,"type":"image","title":"Erfurt-Kraemerbruecke-11.jpg","description":"Kr\u00e4merbr\u00fccke in Erfurt","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134362\/Preview-1280x0\/image","copyrightYear":2019,"license":{"type":"https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de","author":"https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion"}},{"mainImage":false,"type":"image","title":"Erfurt-Kraemerbruecke.jpg","description":"Kr\u00e4merbr\u00fccke in Erfurt","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134288\/Preview-1280x0\/image","copyrightYear":2019,"license":{"type":"https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de","author":"https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion"}},{"mainImage":false,"type":"image","title":"Erfurt-Kraemerbruecke-11.jpg","description":"Kr\u00e4merbr\u00fccke in Erfurt","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/134362\/Preview-1280x0\/image","copyrightYear":2019,"license":{"type":"https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de","author":"https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion"}},{"mainImage":false,"type":"image","title":"Erfurt-Kraemerbruecke-13.jpg","description":"Ansicht der Kr\u00e4merbr\u00fccke, Erfurt","url":"https:\/\/cms.thuecat.org\/o\/adaptive-media\/image\/652340\/Preview-1280x0\/image","copyrightYear":2019,"license":{"type":"https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/deed.de","author":"https:\/\/home.ttgnet.de\/ttg\/projekte\/10006\/90136\/Projektdokumente\/Vergabe%20Rahmenvertrag%20Fotoproduktion"}}] []

View file

@ -1,3 +1,3 @@
tx_thuecat_town
,"uid","pid","remote_id","title","description","managed_by"
,1,10,"https://thuecat.org/resources/043064193523-jcyt","Erfurt","Krämerbrücke, Dom, Alte Synagoge die Thüringer Landeshauptstadt Erfurt hat viele Kulturschätze. Und ein wunderbar junges, studentisches Flair. Eine gute Mischung für alle, die beim Schlendern und Bummeln gerne Städte entdecken: Denn in Erfurt findet man einen wunderbaren mittelalterlichen Stadtkern mit vielen netten Läden, Cafés und Restaurants. Urlauber wie Einheimische bummeln durch die Gassen der Altstadt, aus allen Ecken wispern Geschichte und alte Geschichten. Stolze historische Bürgerhäuser bilden eine der schönsten Altstädte Europas, mittendrin das neugotische Rathaus aus den 1870er-Jahren am Fischmarkt, die spitztürmige St. Severikirche und der mächtige Dom, 1117 erstmals urkundlich erwähnt auf seiner schier endlosen, kaskadenförmigen Freitreppe chillen Jung und Alt gern in der Abendsonne. Ehe sie weiter ziehen zum Tagesausklang in eine der coolen Kneipen und Bars (Tipp: Oma Lilo oder Café Hilgenfeld), in die Wein-Destille am benachbarten Petersberg oder in eins der lässigen Restaurants (Tipp: Mathilda oder Ballenberger), wo zum freundlichen Miteinander eine frische und moderne Küche serviert wird. In Erfurt pulsiert das Leben, hier kann man sich einfach von seiner Neugierde treiben lassen.",
,1,10,"https://thuecat.org/resources/043064193523-jcyt","Erfurt","Krämerbrücke, Dom, Alte Synagoge die Thüringer Landeshauptstadt Erfurt hat viele Kulturschätze. Und ein wunderbar junges, studentisches Flair.Eine gute Mischung für alle, die beim Schlendern und Bummeln gerne Städte entdecken: Denn in Erfurt findet man einen wunderbaren mittelalterlichen Stadtkern mit vielen netten Läden, Cafès und Restaurants. Urlauber wie Einheimische bummeln durch die Gassen der Altstadt, aus allen Ecken wispern Geschichte und alte Geschichten. Stolze historische Bügerhäuser bilden eine der schönsten Altstädte Europas, mittendrin das neugotische Rathaus aus den 1870er-Jahren am Fischmarkt, die spitztürmige St. Severikirche und der mächtige Dom, 1117 erstmals urkundlich erwähnt auf seiner schier endlosen, kaskadenförmigen Freitreppe chillen Jung und Alt gern in der Abendsonne. Ehe sie weiter ziehen zum Tagesausklang in eine der coolen Kneipen und Bars (Tipp: Oma Lilo oder Cafè Hilgenfeld), in die Wein-Destille am benachbarten Petersberg oder in eins der lässigen Restaurants (Tipp: Mathilda oder Ballenberger), wo zum freundlichen Miteinander eine frische und moderne Küche serviert wird.In Erfurt pulsiert das Leben, lassen Sie sich einfach treiben. Von Ihrer Neugierde ...",

Can't render this file because it has a wrong number of fields in line 2.

View file

@ -1,3 +1,3 @@
tx_thuecat_town
,"uid","pid","remote_id","title","description","managed_by"
,1,10,"https://thuecat.org/resources/043064193523-jcyt","Erfurt","Krämerbrücke, Dom, Alte Synagoge die Thüringer Landeshauptstadt Erfurt hat viele Kulturschätze. Und ein wunderbar junges, studentisches Flair. Eine gute Mischung für alle, die beim Schlendern und Bummeln gerne Städte entdecken: Denn in Erfurt findet man einen wunderbaren mittelalterlichen Stadtkern mit vielen netten Läden, Cafés und Restaurants. Urlauber wie Einheimische bummeln durch die Gassen der Altstadt, aus allen Ecken wispern Geschichte und alte Geschichten. Stolze historische Bürgerhäuser bilden eine der schönsten Altstädte Europas, mittendrin das neugotische Rathaus aus den 1870er-Jahren am Fischmarkt, die spitztürmige St. Severikirche und der mächtige Dom, 1117 erstmals urkundlich erwähnt auf seiner schier endlosen, kaskadenförmigen Freitreppe chillen Jung und Alt gern in der Abendsonne. Ehe sie weiter ziehen zum Tagesausklang in eine der coolen Kneipen und Bars (Tipp: Oma Lilo oder Café Hilgenfeld), in die Wein-Destille am benachbarten Petersberg oder in eins der lässigen Restaurants (Tipp: Mathilda oder Ballenberger), wo zum freundlichen Miteinander eine frische und moderne Küche serviert wird. In Erfurt pulsiert das Leben, hier kann man sich einfach von seiner Neugierde treiben lassen.",1
,1,10,"https://thuecat.org/resources/043064193523-jcyt","Erfurt","Krämerbrücke, Dom, Alte Synagoge die Thüringer Landeshauptstadt Erfurt hat viele Kulturschätze. Und ein wunderbar junges, studentisches Flair.Eine gute Mischung für alle, die beim Schlendern und Bummeln gerne Städte entdecken: Denn in Erfurt findet man einen wunderbaren mittelalterlichen Stadtkern mit vielen netten Läden, Cafès und Restaurants. Urlauber wie Einheimische bummeln durch die Gassen der Altstadt, aus allen Ecken wispern Geschichte und alte Geschichten. Stolze historische Bügerhäuser bilden eine der schönsten Altstädte Europas, mittendrin das neugotische Rathaus aus den 1870er-Jahren am Fischmarkt, die spitztürmige St. Severikirche und der mächtige Dom, 1117 erstmals urkundlich erwähnt auf seiner schier endlosen, kaskadenförmigen Freitreppe chillen Jung und Alt gern in der Abendsonne. Ehe sie weiter ziehen zum Tagesausklang in eine der coolen Kneipen und Bars (Tipp: Oma Lilo oder Cafè Hilgenfeld), in die Wein-Destille am benachbarten Petersberg oder in eins der lässigen Restaurants (Tipp: Mathilda oder Ballenberger), wo zum freundlichen Miteinander eine frische und moderne Küche serviert wird.In Erfurt pulsiert das Leben, lassen Sie sich einfach treiben. Von Ihrer Neugierde ...",1

Can't render this file because it has a wrong number of fields in line 2.

View file

@ -0,0 +1,168 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Tests\Functional\Import\EntityMapping;
use PHPUnit\Framework\TestCase;
use WerkraumMedia\ThueCat\Domain\Import\EntityMapper;
use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\JsonDecode;
use WerkraumMedia\ThueCat\Domain\Import\Entity\Base;
use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\ForeignReference;
/**
* @covers \WerkraumMedia\ThueCat\Domain\Import\Converter\ObjectMapping
* @covers \WerkraumMedia\ThueCat\Domain\Import\Entity\Base
* @covers \WerkraumMedia\ThueCat\Domain\Import\Entity\Properies\ForeignReference
*/
class BaseInfosTest extends TestCase
{
/**
* @test
*/
public function instanceOfBaseIsReturnedIfRequestes(): void
{
$subject = new EntityMapper();
$result = $subject->mapDataToEntity([
], Base::class, [
JsonDecode::ACTIVE_LANGUAGE => 'de',
]);
self::assertInstanceOf(Base::class, $result);
}
/**
* @test
*/
public function returnsDefaultValuesIfNotProvidedForMapping(): void
{
$subject = new EntityMapper();
$result = $subject->mapDataToEntity([
], Base::class, [
JsonDecode::ACTIVE_LANGUAGE => 'de',
]);
self::assertInstanceOf(Base::class, $result);
self::assertSame('', $result->getId());
self::assertSame('', $result->getName());
self::assertSame('', $result->getDescription());
self::assertSame('', $result->getUrl());
self::assertNull($result->getPhoto());
self::assertSame([], $result->getImages());
self::assertNull($result->getManagedBy());
}
/**
* @test
*/
public function mapsIncomingDataToProperties(): void
{
$subject = new EntityMapper();
$result = $subject->mapDataToEntity([
'@id' => 'https://thuecat.org/resources/835224016581-dara',
'schema:name' => 'The name of the Thing',
'schema:description' => 'This is some long description describing this Thing.',
'schema:url' => 'https://example.com/the-thing',
], Base::class, [
JsonDecode::ACTIVE_LANGUAGE => 'de',
]);
self::assertInstanceOf(Base::class, $result);
self::assertSame('https://thuecat.org/resources/835224016581-dara', $result->getId());
self::assertSame('The name of the Thing', $result->getName());
self::assertSame('This is some long description describing this Thing.', $result->getDescription());
self::assertSame('https://example.com/the-thing', $result->getUrl());
}
/**
* @test
*/
public function mapsIncomingPhoto(): void
{
$subject = new EntityMapper();
$result = $subject->mapDataToEntity([
'schema:photo' => [
'@id' => 'https://thuecat.org/resources/835224016581-dara',
],
], Base::class, [
JsonDecode::ACTIVE_LANGUAGE => 'de',
]);
self::assertInstanceOf(Base::class, $result);
self::assertInstanceOf(ForeignReference::class, $result->getPhoto());
self::assertSame('https://thuecat.org/resources/835224016581-dara', $result->getPhoto()->getId());
}
/**
* @test
*/
public function mapsIncomingImages(): void
{
$subject = new EntityMapper();
$result = $subject->mapDataToEntity([
'schema:image' => [
[
'@id' => 'https://thuecat.org/resources/835224016581-1st',
],
[
'@id' => 'https://thuecat.org/resources/835224016581-2nd',
],
],
], Base::class, [
JsonDecode::ACTIVE_LANGUAGE => 'de',
]);
self::assertInstanceOf(Base::class, $result);
self::assertIsArray($result->getImages());
foreach ($result->getImages() as $image) {
self::assertInstanceOf(ForeignReference::class, $image);
}
self::assertSame('https://thuecat.org/resources/835224016581-1st', $result->getImages()[0]->getId());
self::assertSame('https://thuecat.org/resources/835224016581-2nd', $result->getImages()[1]->getId());
}
/**
* @test
*/
public function mapsIncomingManagedBy(): void
{
$subject = new EntityMapper();
$result = $subject->mapDataToEntity([
'thuecat:contentResponsible' => [
'@id' => 'https://thuecat.org/resources/835224016581-1st',
],
], Base::class, [
JsonDecode::ACTIVE_LANGUAGE => 'de',
]);
self::assertInstanceOf(Base::class, $result);
self::assertInstanceOf(ForeignReference::class, $result->getManagedBy());
self::assertSame('https://thuecat.org/resources/835224016581-1st', $result->getManagedBy()->getId());
}
}

View file

@ -0,0 +1,347 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Tests\Functional\Import\EntityMapping;
use PHPUnit\Framework\TestCase;
use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\JsonDecode;
/**
* @covers \WerkraumMedia\ThueCat\Domain\Import\EntityMapper\JsonDecode;
*/
class JsonDecodingTest extends TestCase
{
/**
* @test
*/
public function canBeCreated(): void
{
$subject = new JsonDecode();
self::assertInstanceOf(
JsonDecode::class,
$subject
);
}
/**
* @test
*/
public function decodesPropertyWithMultipleLanguagesProvidingActiveOne(): void
{
$subject = new JsonDecode();
$result = $subject->decode((string) json_encode([
'schema:name' => [
[
'@language' => 'de',
'@value' => 'Deutscher Text',
],
[
'@language' => 'en',
'@value' => 'English Text',
],
],
]), 'json', [
JsonDecode::ACTIVE_LANGUAGE => 'en',
]);
self::assertSame([
'name' => 'English Text',
], $result);
}
/**
* @test
*/
public function decodesPropertyWithSingleLanguageMatchingActive(): void
{
$subject = new JsonDecode();
$result = $subject->decode((string) json_encode([
'schema:name' => [
'@language' => 'en',
'@value' => 'English Text',
],
]), 'json', [
JsonDecode::ACTIVE_LANGUAGE => 'en',
]);
self::assertSame([
'name' => 'English Text',
], $result);
}
/**
* @test
*/
public function decodesPropertyWithSingleLanguageNotMatchingActive(): void
{
$subject = new JsonDecode();
$result = $subject->decode((string) json_encode([
'schema:name' => [
'@language' => 'de',
'@value' => 'German Text',
],
]), 'json', [
JsonDecode::ACTIVE_LANGUAGE => 'en',
]);
self::assertSame([
'name' => '',
], $result);
}
/**
* @test
*/
public function decodesPropertyWithMultipleLanguagesAndFormatsProvidingActiveLanguage(): void
{
$subject = new JsonDecode();
$result = $subject->decode((string) json_encode([
'schema:description' => [
0 => [
'@language' => 'en',
'@value' => 'English plain',
],
1 => [
'@language' => 'de',
'@value' => 'Deutsch plain',
],
2 => [
'@id' => 'genid-7bb7d92bd6624bdf84634c86e8acdbb4-b1',
'@type' => [
0 => 'thuecat:Html',
],
'schema:value' => [
'@language' => 'de',
'@value' => 'Deutsch HTML',
],
],
3 => [
'@id' => 'genid-7bb7d92bd6624bdf84634c86e8acdbb4-b2',
'@type' => [
0 => 'thuecat:Html',
],
'schema:value' => [
'@language' => 'en',
'@value' => 'English HTML',
],
],
],
]), 'json', [
JsonDecode::ACTIVE_LANGUAGE => 'en',
]);
self::assertSame([
'description' => 'English plain',
], $result);
}
/**
* @test
*/
public function decodesSingleValueNotRelatedToLanguage(): void
{
$subject = new JsonDecode();
$result = $subject->decode((string) json_encode([
'schema:geo' => [
'schema:latitude' => [
'@type' => 'schema:Number',
'@value' => '50.978772',
],
'schema:longitude' => [
'@type' => 'schema:Number',
'@value' => '11.031622',
],
],
]), 'json', [
JsonDecode::ACTIVE_LANGUAGE => 'en',
]);
self::assertSame([
'geo' => [
'latitude' => '50.978772',
'longitude' => '11.031622',
],
], $result);
}
/**
* @test
*/
public function decodesNestedObjectStructures(): void
{
$subject = new JsonDecode();
$result = $subject->decode((string) json_encode([
'@id' => 'https://thuecat.org/resources/835224016581-dara',
'schema:name' => [
'@language' => 'en',
'@value' => 'Cathedral of St. Mary',
],
'schema:photo' => [
'@id' => 'https://thuecat.org/resources/dms_5159216',
],
'schema:image' => [
0 => [
'@id' => 'https://thuecat.org/resources/dms_5159186',
],
1 => [
'@id' => 'https://thuecat.org/resources/dms_5159216',
],
],
'thuecat:contentResponsible' => [
'@id' => 'https://thuecat.org/resources/018132452787-ngbe',
],
]), 'json', [
JsonDecode::ACTIVE_LANGUAGE => 'en',
]);
self::assertSame([
'id' => 'https://thuecat.org/resources/835224016581-dara',
'name' => 'Cathedral of St. Mary',
'photo' => [
'id' => 'https://thuecat.org/resources/dms_5159216',
],
'image' => [
0 => [
'id' => 'https://thuecat.org/resources/dms_5159186',
],
1 => [
'id' => 'https://thuecat.org/resources/dms_5159216',
],
],
'contentResponsible' => [
'id' => 'https://thuecat.org/resources/018132452787-ngbe',
],
], $result);
}
/**
* @test
*/
public function decodesOpeningHours(): void
{
$subject = new JsonDecode();
$result = $subject->decode((string) json_encode([
'schema:openingHoursSpecification' => [
0 => [
'@id' => 'genid-7bb7d92bd6624bdf84634c86e8acdbb4-b4',
'schema:closes' => [
'@type' => 'schema:Time',
'@value' => '18:00:00',
],
'schema:dayOfWeek' => [
0 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Saturday',
],
1 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Friday',
],
2 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Thursday',
],
3 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Tuesday',
],
4 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Monday',
],
5 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Wednesday',
],
],
'schema:opens' => [
'@type' => 'schema:Time',
'@value' => '09:30:00',
],
'schema:validFrom' => [
'@type' => 'schema:Date',
'@value' => '2021-05-01',
],
'schema:validThrough' => [
'@type' => 'schema:Date',
'@value' => '2021-10-31',
],
],
1 => [
'@id' => 'genid-7bb7d92bd6624bdf84634c86e8acdbb4-b7',
'schema:closes' => [
'@type' => 'schema:Time',
'@value' => '17:00:00',
],
'schema:dayOfWeek' => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Sunday',
],
'schema:opens' => [
'@type' => 'schema:Time',
'@value' => '13:00:00',
],
'schema:validFrom' => [
'@type' => 'schema:Date',
'@value' => '2021-11-01',
],
'schema:validThrough' => [
'@type' => 'schema:Date',
'@value' => '2022-04-30',
],
],
],
]), 'json', [
JsonDecode::ACTIVE_LANGUAGE => 'en',
]);
self::assertSame([
'openingHoursSpecification' => [
0 => [
'id' => 'genid-7bb7d92bd6624bdf84634c86e8acdbb4-b4',
'closes' => '18:00:00',
'dayOfWeek' => [
0 => 'schema:Saturday',
1 => 'schema:Friday',
2 => 'schema:Thursday',
3 => 'schema:Tuesday',
4 => 'schema:Monday',
5 => 'schema:Wednesday',
],
'opens' => '09:30:00',
'validFrom' => '2021-05-01',
'validThrough' => '2021-10-31',
],
1 => [
'id' => 'genid-7bb7d92bd6624bdf84634c86e8acdbb4-b7',
'closes' => '17:00:00',
'dayOfWeek' => 'schema:Sunday',
'opens' => '13:00:00',
'validFrom' => '2021-11-01',
'validThrough' => '2022-04-30',
],
],
], $result);
}
}

View file

@ -0,0 +1,239 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
namespace WerkraumMedia\ThueCat\Tests\Functional\ObjectMapping;
use PHPUnit\Framework\TestCase;
use WerkraumMedia\ThueCat\Domain\Import\EntityMapper;
use WerkraumMedia\ThueCat\Domain\Import\EntityMapper\JsonDecode;
use WerkraumMedia\ThueCat\Domain\Import\Entity\Place;
use WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\Address;
/**
* @covers \WerkraumMedia\ThueCat\Domain\Import\EntityMapper
* @covers \WerkraumMedia\ThueCat\Domain\Import\EntityMapper\JsonDecode
* @uses \WerkraumMedia\ThueCat\Domain\Import\Entity\Place
* @uses \WerkraumMedia\ThueCat\Domain\Import\Entity\Properties\Address
*/
class PlaceInfosTest extends TestCase
{
/**
* @test
*/
public function instanceOfPlaceIsReturnedIfRequestes(): void
{
$subject = new EntityMapper();
$result = $subject->mapDataToEntity([
], Place::class, [
JsonDecode::ACTIVE_LANGUAGE => 'de',
]);
self::assertInstanceOf(Place::class, $result);
}
/**
* @test
*/
public function returnsDefaultValuesIfNotProvidedForMapping(): void
{
$subject = new EntityMapper();
$result = $subject->mapDataToEntity([
], Place::class, [
JsonDecode::ACTIVE_LANGUAGE => 'de',
]);
self::assertInstanceOf(Place::class, $result);
self::assertSame([], $result->getOpeningHoursSpecification());
}
/**
* @test
*/
public function mapsIncomingOpeningHoursSpecificaton(): void
{
$subject = new EntityMapper();
$result = $subject->mapDataToEntity([
'schema:openingHoursSpecification' => [
0 => [
'schema:closes' => [
'@type' => 'schema:Time',
'@value' => '18:00:00',
],
'schema:dayOfWeek' => [
0 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Saturday',
],
1 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Friday',
],
2 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Thursday',
],
3 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Tuesday',
],
4 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Monday',
],
5 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Wednesday',
],
],
'schema:opens' => [
'@type' => 'schema:Time',
'@value' => '09:30:00',
],
'schema:validFrom' => [
'@type' => 'schema:Date',
'@value' => '2021-05-01',
],
'schema:validThrough' => [
'@type' => 'schema:Date',
'@value' => '2021-10-31',
],
],
1 => [
'schema:closes' => [
'@type' => 'schema:Time',
'@value' => '18:00:00',
],
'schema:dayOfWeek' => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Sunday',
],
'schema:opens' => [
'@type' => 'schema:Time',
'@value' => '13:00:00',
],
'schema:validFrom' => [
'@type' => 'schema:Date',
'@value' => '2021-05-01',
],
'schema:validThrough' => [
'@type' => 'schema:Date',
'@value' => '2021-10-31',
],
],
],
], Place::class, [
JsonDecode::ACTIVE_LANGUAGE => 'de',
]);
self::assertInstanceOf(Place::class, $result);
self::assertCount(2, $result->getOpeningHoursSpecification());
self::assertSame('18:00:00', $result->getOpeningHoursSpecification()[0]->getCloses()->format('H:i:s'));
self::assertSame('09:30:00', $result->getOpeningHoursSpecification()[0]->getOpens()->format('H:i:s'));
self::assertSame('2021-05-01', $result->getOpeningHoursSpecification()[0]->getValidFrom()->format('Y-m-d'));
self::assertSame('2021-10-31', $result->getOpeningHoursSpecification()[0]->getValidThrough()->format('Y-m-d'));
self::assertSame([
'Saturday',
'Friday',
'Thursday',
'Tuesday',
'Monday',
'Wednesday',
], $result->getOpeningHoursSpecification()[0]->getDaysOfWeek());
self::assertSame('18:00:00', $result->getOpeningHoursSpecification()[1]->getCloses()->format('H:i:s'));
self::assertSame('13:00:00', $result->getOpeningHoursSpecification()[1]->getOpens()->format('H:i:s'));
self::assertSame('2021-05-01', $result->getOpeningHoursSpecification()[1]->getValidFrom()->format('Y-m-d'));
self::assertSame('2021-10-31', $result->getOpeningHoursSpecification()[1]->getValidThrough()->format('Y-m-d'));
self::assertSame(['Sunday'], $result->getOpeningHoursSpecification()[1]->getDaysOfWeek());
}
/**
* @test
*/
public function mapsIncomingAddress(): void
{
$subject = new EntityMapper();
$result = $subject->mapDataToEntity([
'schema:address' => [
'schema:addressLocality' => [
'@language' => 'de',
'@value' => 'Erfurt',
],
'schema:postalCode' => [
0 => [
'@language' => 'de',
'@value' => '99084',
],
1 => [
'@language' => 'en',
'@value' => '99084',
],
],
'schema:telephone' => [
0 => [
'@language' => 'de',
'@value' => '+49 361 6461265',
],
1 => [
'@language' => 'en',
'@value' => '+49 361 6461265',
],
],
'schema:email' => [
0 => [
'@language' => 'de',
'@value' => 'dominformation@domberg-erfurt.de',
],
1 => [
'@language' => 'en',
'@value' => 'dominformation@domberg-erfurt.de',
],
],
'schema:streetAddress' => [
0 => [
'@language' => 'de',
'@value' => 'Domstufen 1',
],
1 => [
'@language' => 'en',
'@value' => 'Domstufen 1',
],
],
],
], Place::class, [
JsonDecode::ACTIVE_LANGUAGE => 'de',
]);
self::assertInstanceOf(Place::class, $result);
self::assertInstanceOf(Address::class, $result->getAddress());
self::assertSame('Domstufen 1', $result->getAddress()->getStreetAddress());
self::assertSame('Erfurt', $result->getAddress()->getAddressLocality());
self::assertSame('99084', $result->getAddress()->getPostalCode());
self::assertSame('+49 361 6461265', $result->getAddress()->getTelephone());
self::assertSame('', $result->getAddress()->getFaxNumber());
self::assertSame('dominformation@domberg-erfurt.de', $result->getAddress()->getEmail());
}
}

View file

@ -53,14 +53,6 @@ use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase as TestCase;
* @uses \WerkraumMedia\ThueCat\Domain\Import\Importer
* @uses \WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData
* @uses \WerkraumMedia\ThueCat\Domain\Import\Importer\LanguageHandling
* @uses \WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser
* @uses \WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Address
* @uses \WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\GenericFields
* @uses \WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\LanguageValues
* @uses \WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Media
* @uses \WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Offers
* @uses \WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\OpeningHours
* @uses \WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\OpeningHours
* @uses \WerkraumMedia\ThueCat\Domain\Import\Model\EntityCollection
* @uses \WerkraumMedia\ThueCat\Domain\Import\Model\GenericEntity
* @uses \WerkraumMedia\ThueCat\Domain\Import\RequestFactory

View file

@ -1,145 +0,0 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import\Converter;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use WerkraumMedia\ThueCat\Domain\Import\Converter\Converter;
use WerkraumMedia\ThueCat\Domain\Import\Converter\Organisation;
use WerkraumMedia\ThueCat\Domain\Import\Importer\LanguageHandling;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser;
use WerkraumMedia\ThueCat\Domain\Import\Model\EntityCollection;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration;
/**
* @covers \WerkraumMedia\ThueCat\Domain\Import\Converter\Organisation
*
* @uses \WerkraumMedia\ThueCat\Domain\Import\Model\EntityCollection
* @uses \WerkraumMedia\ThueCat\Domain\Import\Model\GenericEntity
*/
class OrganisationTest extends TestCase
{
use ProphecyTrait;
/**
* @test
*/
public function instanceCanBeCreated(): void
{
$parser = $this->prophesize(Parser::class);
$language = $this->prophesize(LanguageHandling::class);
$subject = new Organisation(
$parser->reveal(),
$language->reveal()
);
self::assertInstanceOf(Organisation::class, $subject);
}
/**
* @test
*/
public function isInstanceOfConverter(): void
{
$parser = $this->prophesize(Parser::class);
$language = $this->prophesize(LanguageHandling::class);
$subject = new Organisation(
$parser->reveal(),
$language->reveal()
);
self::assertInstanceOf(Converter::class, $subject);
}
/**
* @test
*/
public function canConvertTouristMarketingCompany(): void
{
$parser = $this->prophesize(Parser::class);
$language = $this->prophesize(LanguageHandling::class);
$subject = new Organisation(
$parser->reveal(),
$language->reveal()
);
self::assertTrue($subject->canConvert([
'thuecat:TouristMarketingCompany',
'schema:Thing',
'ttgds:Organization',
]));
}
/**
* @test
*/
public function convertsJsonIdToGenericEntity(): void
{
$jsonLD = [
'@id' => 'https://example.com/resources/018132452787-ngbe',
'schema:name' => [
'@value' => 'Title',
],
'schema:description' => [
'@value' => 'Description',
],
];
$siteLanguage = $this->prophesize(SiteLanguage::class);
$language = $this->prophesize(LanguageHandling::class);
$language->getDefaultLanguage(10)->willReturn($siteLanguage->reveal());
$parser = $this->prophesize(Parser::class);
$parser->getId($jsonLD)->willReturn('https://example.com/resources/018132452787-ngbe');
$parser->getTitle($jsonLD, $siteLanguage->reveal())->willReturn('Title');
$parser->getDescription($jsonLD, $siteLanguage->reveal())->willReturn('Description');
$configuration = $this->prophesize(ImportConfiguration::class);
$configuration->getStoragePid()->willReturn(10);
$subject = new Organisation(
$parser->reveal(),
$language->reveal()
);
$entities = $subject->convert($jsonLD, $configuration->reveal());
self::assertInstanceOf(EntityCollection::class, $entities);
self::assertCount(1, $entities->getEntities());
$entity = $entities->getEntities()[0];
self::assertSame(10, $entity->getTypo3StoragePid());
self::assertSame('tx_thuecat_organisation', $entity->getTypo3DatabaseTableName());
self::assertSame('https://example.com/resources/018132452787-ngbe', $entity->getRemoteId());
self::assertSame([
'title' => 'Title',
'description' => 'Description',
], $entity->getData());
}
}

View file

@ -1,108 +0,0 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import\Converter;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use WerkraumMedia\ThueCat\Domain\Import\Converter\Converter;
use WerkraumMedia\ThueCat\Domain\Import\Converter\Registry;
/**
* @covers \WerkraumMedia\ThueCat\Domain\Import\Converter\Registry
*/
class RegistryTest extends TestCase
{
use ProphecyTrait;
/**
* @test
*/
public function canBeCreated(): void
{
$subject = new Registry();
self::assertInstanceOf(Registry::class, $subject);
}
/**
* @test
*/
public function allowsRegistrationOfConverter(): void
{
$subject = new Registry();
$converter = $this->prophesize(Converter::class);
$subject->registerConverter($converter->reveal());
self::assertTrue(true);
}
/**
* @test
*/
public function returnsConverterForMatchingType(): void
{
$subject = new Registry();
$converter = $this->prophesize(Converter::class);
$converter->canConvert(['thuecat:Entity'])->willReturn(true);
$subject->registerConverter($converter->reveal());
$result = $subject->getConverterBasedOnType(['thuecat:Entity']);
self::assertSame($converter->reveal(), $result);
}
/**
* @test
*/
public function returnsFirstMatchingConverterForMatchingType(): void
{
$subject = new Registry();
$converter1 = $this->prophesize(Converter::class);
$converter1->canConvert(['thuecat:Entity'])->willReturn(true);
$converter2 = $this->prophesize(Converter::class);
$converter2->canConvert(['thuecat:Entity'])->willReturn(true);
$subject->registerConverter($converter1->reveal());
$subject->registerConverter($converter2->reveal());
$result = $subject->getConverterBasedOnType(['thuecat:Entity']);
self::assertSame($converter1->reveal(), $result);
}
/**
* @test
*/
public function returnsNullForNoMatchingConverter(): void
{
$subject = new Registry();
$converter1 = $this->prophesize(Converter::class);
$converter1->canConvert(['thuecat:Entity'])->willReturn(false);
$subject->registerConverter($converter1->reveal());
$result = $subject->getConverterBasedOnType(['thuecat:Entity']);
self::assertNull($result);
}
}

View file

@ -1,335 +0,0 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import\Converter;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use WerkraumMedia\ThueCat\Domain\Import\Converter\TouristAttraction;
use WerkraumMedia\ThueCat\Domain\Import\Importer\LanguageHandling;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Offers;
use WerkraumMedia\ThueCat\Domain\Import\Model\EntityCollection;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration;
use WerkraumMedia\ThueCat\Domain\Model\Backend\Organisation;
use WerkraumMedia\ThueCat\Domain\Model\Backend\Town;
use WerkraumMedia\ThueCat\Domain\Repository\Backend\OrganisationRepository;
use WerkraumMedia\ThueCat\Domain\Repository\Backend\TownRepository;
/**
* @covers \WerkraumMedia\ThueCat\Domain\Import\Converter\TouristAttraction
*
* @uses \WerkraumMedia\ThueCat\Domain\Import\Model\EntityCollection
* @uses \WerkraumMedia\ThueCat\Domain\Import\Model\GenericEntity
*/
class TouristAttractionTest extends TestCase
{
use ProphecyTrait;
/**
* @test
*/
public function canBeCreated(): void
{
$parser = $this->prophesize(Parser::class);
$parserForOffers = $this->prophesize(Offers::class);
$language = $this->prophesize(LanguageHandling::class);
$organisationRepository = $this->prophesize(OrganisationRepository::class);
$townRepository = $this->prophesize(TownRepository::class);
$subject = new TouristAttraction(
$parser->reveal(),
$parserForOffers->reveal(),
$language->reveal(),
$organisationRepository->reveal(),
$townRepository->reveal()
);
self::assertInstanceOf(TouristAttraction::class, $subject);
}
/**
* @test
*/
public function canConvert(): void
{
$parser = $this->prophesize(Parser::class);
$parserForOffers = $this->prophesize(Offers::class);
$language = $this->prophesize(LanguageHandling::class);
$organisationRepository = $this->prophesize(OrganisationRepository::class);
$townRepository = $this->prophesize(TownRepository::class);
$subject = new TouristAttraction(
$parser->reveal(),
$parserForOffers->reveal(),
$language->reveal(),
$organisationRepository->reveal(),
$townRepository->reveal()
);
self::assertTrue($subject->canConvert(['schema:TouristAttraction']));
}
/**
* @test
*/
public function convertsWithoutRelations(): void
{
$jsonLD = [
'@id' => 'https://example.com/resources/018132452787-ngbe',
'thuecat:managedBy' => [
'@id' => 'https://example.com/resources/018132452787-xxxx',
],
'schema:containedInPlace' => [
[
'@id' => 'https://example.com/resources/043064193523-jcyt',
],
[
'@id' => 'https://example.com/resources/573211638937-gmqb',
],
],
'schema:name' => [
'@value' => 'Title',
],
'schema:description' => [
[
'@value' => 'Description',
],
],
];
$siteLanguage = $this->prophesize(SiteLanguage::class);
$siteLanguage->getLanguageId()->willReturn(2);
$language = $this->prophesize(LanguageHandling::class);
$language->getLanguages(10)->willReturn([$siteLanguage->reveal()]);
$parser = $this->prophesize(Parser::class);
$parser->getManagerId($jsonLD)->willReturn('https://example.com/resources/018132452787-xxxx');
$parser->getContainedInPlaceIds($jsonLD)->willReturn([
'https://example.com/resources/043064193523-jcyt',
'https://example.com/resources/573211638937-gmqb',
]);
$parser->getId($jsonLD)->willReturn('https://example.com/resources/018132452787-ngbe');
$parser->getTitle($jsonLD, $siteLanguage->reveal())->willReturn('Title');
$parser->getDescription($jsonLD, $siteLanguage->reveal())->willReturn('Description');
$parser->getOpeningHours($jsonLD)->willReturn([]);
$parser->getAddress($jsonLD)->willReturn([]);
$parser->getMedia($jsonLD)->willReturn([]);
$parserForOffers = $this->prophesize(Offers::class);
$parserForOffers->get($jsonLD, $siteLanguage->reveal())->willReturn([]);
$organisationRepository = $this->prophesize(OrganisationRepository::class);
$townRepository = $this->prophesize(TownRepository::class);
$configuration = $this->prophesize(ImportConfiguration::class);
$configuration->getStoragePid()->willReturn(10);
$subject = new TouristAttraction(
$parser->reveal(),
$parserForOffers->reveal(),
$language->reveal(),
$organisationRepository->reveal(),
$townRepository->reveal()
);
$entities = $subject->convert($jsonLD, $configuration->reveal());
self::assertInstanceOf(EntityCollection::class, $entities);
self::assertCount(1, $entities->getEntities());
$entity = $entities->getEntities()[0];
self::assertSame(10, $entity->getTypo3StoragePid());
self::assertSame(2, $entity->getTypo3SystemLanguageUid());
self::assertSame('tx_thuecat_tourist_attraction', $entity->getTypo3DatabaseTableName());
self::assertSame('https://example.com/resources/018132452787-ngbe', $entity->getRemoteId());
self::assertSame([
'title' => 'Title',
'description' => 'Description',
'managed_by' => 0,
'town' => 0,
'opening_hours' => '[]',
'address' => '[]',
'media' => '[]',
'offers' => '[]',
], $entity->getData());
}
/**
* @test
*/
public function convertsWithRelations(): void
{
$jsonLD = [
'@id' => 'https://example.com/resources/018132452787-ngbe',
'thuecat:managedBy' => [
'@id' => 'https://example.com/resources/018132452787-xxxx',
],
'schema:containedInPlace' => [
[
'@id' => 'https://example.com/resources/043064193523-jcyt',
],
[
'@id' => 'https://example.com/resources/573211638937-gmqb',
],
],
'schema:name' => [
'@value' => 'Title',
],
'schema:description' => [
[
'@value' => 'Description',
],
],
];
$siteLanguage = $this->prophesize(SiteLanguage::class);
$siteLanguage->getLanguageId()->willReturn(2);
$language = $this->prophesize(LanguageHandling::class);
$language->getLanguages(10)->willReturn([$siteLanguage->reveal()]);
$parser = $this->prophesize(Parser::class);
$parser->getManagerId($jsonLD)->willReturn('https://example.com/resources/018132452787-xxxx');
$parser->getContainedInPlaceIds($jsonLD)->willReturn([
'https://example.com/resources/043064193523-jcyt',
'https://example.com/resources/573211638937-gmqb',
]);
$parser->getId($jsonLD)->willReturn('https://example.com/resources/018132452787-ngbe');
$parser->getTitle($jsonLD, $siteLanguage->reveal())->willReturn('Title');
$parser->getDescription($jsonLD, $siteLanguage->reveal())->willReturn('Description');
$parser->getOpeningHours($jsonLD)->willReturn([]);
$parser->getAddress($jsonLD)->willReturn([]);
$parser->getMedia($jsonLD)->willReturn([]);
$parserForOffers = $this->prophesize(Offers::class);
$parserForOffers->get($jsonLD, $siteLanguage->reveal())->willReturn([]);
$organisation = $this->prophesize(Organisation::class);
$organisation->getUid()->willReturn(10);
$organisationRepository = $this->prophesize(OrganisationRepository::class);
$organisationRepository->findOneByRemoteId('https://example.com/resources/018132452787-xxxx')->willReturn($organisation->reveal());
$town = $this->prophesize(Town::class);
$town->getUid()->willReturn(20);
$townRepository = $this->prophesize(TownRepository::class);
$townRepository->findOneByRemoteIds([
'https://example.com/resources/043064193523-jcyt',
'https://example.com/resources/573211638937-gmqb',
])->willReturn($town->reveal());
$configuration = $this->prophesize(ImportConfiguration::class);
$configuration->getStoragePid()->willReturn(10);
$subject = new TouristAttraction(
$parser->reveal(),
$parserForOffers->reveal(),
$language->reveal(),
$organisationRepository->reveal(),
$townRepository->reveal()
);
$entities = $subject->convert($jsonLD, $configuration->reveal());
self::assertInstanceOf(EntityCollection::class, $entities);
self::assertCount(1, $entities->getEntities());
$entity = $entities->getEntities()[0];
self::assertSame(10, $entity->getTypo3StoragePid());
self::assertSame(2, $entity->getTypo3SystemLanguageUid());
self::assertSame('tx_thuecat_tourist_attraction', $entity->getTypo3DatabaseTableName());
self::assertSame('https://example.com/resources/018132452787-ngbe', $entity->getRemoteId());
self::assertSame([
'title' => 'Title',
'description' => 'Description',
'managed_by' => 10,
'town' => 20,
'opening_hours' => '[]',
'address' => '[]',
'media' => '[]',
'offers' => '[]',
], $entity->getData());
}
/**
* @test
*/
public function skipsLanguagesWithoutTitle(): void
{
$jsonLD = [
'@id' => 'https://example.com/resources/018132452787-ngbe',
'thuecat:managedBy' => [
'@id' => 'https://example.com/resources/018132452787-xxxx',
],
'schema:containedInPlace' => [
[
'@id' => 'https://example.com/resources/043064193523-jcyt',
],
[
'@id' => 'https://example.com/resources/573211638937-gmqb',
],
],
'schema:name' => [
'@value' => 'Title',
],
'schema:description' => [
[
'@value' => 'Description',
],
],
];
$siteLanguage = $this->prophesize(SiteLanguage::class);
$siteLanguage->getLanguageId()->willReturn(2);
$language = $this->prophesize(LanguageHandling::class);
$language->getLanguages(10)->willReturn([$siteLanguage->reveal()]);
$parser = $this->prophesize(Parser::class);
$parser->getManagerId($jsonLD)->willReturn('https://example.com/resources/018132452787-xxxx');
$parser->getContainedInPlaceIds($jsonLD)->willReturn([
'https://example.com/resources/043064193523-jcyt',
'https://example.com/resources/573211638937-gmqb',
]);
$parser->getTitle($jsonLD, $siteLanguage->reveal())->willReturn('');
$parserForOffers = $this->prophesize(Offers::class);
$organisationRepository = $this->prophesize(OrganisationRepository::class);
$townRepository = $this->prophesize(TownRepository::class);
$configuration = $this->prophesize(ImportConfiguration::class);
$configuration->getStoragePid()->willReturn(10);
$subject = new TouristAttraction(
$parser->reveal(),
$parserForOffers->reveal(),
$language->reveal(),
$organisationRepository->reveal(),
$townRepository->reveal()
);
$entities = $subject->convert($jsonLD, $configuration->reveal());
self::assertInstanceOf(EntityCollection::class, $entities);
self::assertCount(0, $entities->getEntities());
}
}

View file

@ -1,272 +0,0 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import\Converter;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use WerkraumMedia\ThueCat\Domain\Import\Converter\Converter;
use WerkraumMedia\ThueCat\Domain\Import\Converter\TouristInformation;
use WerkraumMedia\ThueCat\Domain\Import\Importer\LanguageHandling;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser;
use WerkraumMedia\ThueCat\Domain\Import\Model\EntityCollection;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration;
use WerkraumMedia\ThueCat\Domain\Model\Backend\Organisation;
use WerkraumMedia\ThueCat\Domain\Model\Backend\Town;
use WerkraumMedia\ThueCat\Domain\Repository\Backend\OrganisationRepository;
use WerkraumMedia\ThueCat\Domain\Repository\Backend\TownRepository;
/**
* @covers \WerkraumMedia\ThueCat\Domain\Import\Converter\TouristInformation
*
* @uses \WerkraumMedia\ThueCat\Domain\Import\Model\EntityCollection
* @uses \WerkraumMedia\ThueCat\Domain\Import\Model\GenericEntity
*/
class TouristInformationTest extends TestCase
{
use ProphecyTrait;
/**
* @test
*/
public function instanceCanBeCreated(): void
{
$parser = $this->prophesize(Parser::class);
$language = $this->prophesize(LanguageHandling::class);
$organisationRepository = $this->prophesize(OrganisationRepository::class);
$townRepository = $this->prophesize(TownRepository::class);
$subject = new TouristInformation(
$parser->reveal(),
$language->reveal(),
$organisationRepository->reveal(),
$townRepository->reveal()
);
self::assertInstanceOf(TouristInformation::class, $subject);
}
/**
* @test
*/
public function isInstanceOfConverter(): void
{
$parser = $this->prophesize(Parser::class);
$language = $this->prophesize(LanguageHandling::class);
$organisationRepository = $this->prophesize(OrganisationRepository::class);
$townRepository = $this->prophesize(TownRepository::class);
$subject = new TouristInformation(
$parser->reveal(),
$language->reveal(),
$organisationRepository->reveal(),
$townRepository->reveal()
);
self::assertInstanceOf(Converter::class, $subject);
}
/**
* @test
*/
public function canConvertTouristMarketingCompany(): void
{
$parser = $this->prophesize(Parser::class);
$language = $this->prophesize(LanguageHandling::class);
$organisationRepository = $this->prophesize(OrganisationRepository::class);
$townRepository = $this->prophesize(TownRepository::class);
$subject = new TouristInformation(
$parser->reveal(),
$language->reveal(),
$organisationRepository->reveal(),
$townRepository->reveal()
);
self::assertTrue($subject->canConvert([
'thuecat:TouristInformation',
]));
}
/**
* @test
*/
public function convertsJsonIdToGenericEntityWithoutRelations(): void
{
$jsonLD = [
'@id' => 'https://example.com/resources/018132452787-ngbe',
'thuecat:managedBy' => [
'@id' => 'https://example.com/resources/018132452787-xxxx',
],
'schema:containedInPlace' => [
[
'@id' => 'https://example.com/resources/043064193523-jcyt',
],
[
'@id' => 'https://example.com/resources/573211638937-gmqb',
],
],
'schema:name' => [
'@value' => 'Title',
],
'schema:description' => [
[
'@value' => 'Description',
],
],
];
$siteLanguage = $this->prophesize(SiteLanguage::class);
$language = $this->prophesize(LanguageHandling::class);
$language->getDefaultLanguage(10)->willReturn($siteLanguage);
$parser = $this->prophesize(Parser::class);
$parser->getManagerId($jsonLD)->willReturn('https://example.com/resources/018132452787-xxxx');
$parser->getContainedInPlaceIds($jsonLD)->willReturn([
'https://example.com/resources/043064193523-jcyt',
'https://example.com/resources/573211638937-gmqb',
]);
$parser->getId($jsonLD)->willReturn('https://example.com/resources/018132452787-ngbe');
$parser->getTitle($jsonLD, $siteLanguage->reveal())->willReturn('Title');
$parser->getDescription($jsonLD, $siteLanguage->reveal())->willReturn('Description');
$organisationRepository = $this->prophesize(OrganisationRepository::class);
$organisationRepository->findOneByRemoteId('https://example.com/resources/018132452787-xxxx')
->willReturn(null);
$townRepository = $this->prophesize(TownRepository::class);
$townRepository->findOneByRemoteIds([
'https://example.com/resources/043064193523-jcyt',
'https://example.com/resources/573211638937-gmqb',
])->willReturn(null);
$configuration = $this->prophesize(ImportConfiguration::class);
$configuration->getStoragePid()->willReturn(10);
$subject = new TouristInformation(
$parser->reveal(),
$language->reveal(),
$organisationRepository->reveal(),
$townRepository->reveal()
);
$entities = $subject->convert($jsonLD, $configuration->reveal());
self::assertInstanceOf(EntityCollection::class, $entities);
self::assertCount(1, $entities->getEntities());
$entity = $entities->getEntities()[0];
self::assertSame(10, $entity->getTypo3StoragePid());
self::assertSame('tx_thuecat_tourist_information', $entity->getTypo3DatabaseTableName());
self::assertSame('https://example.com/resources/018132452787-ngbe', $entity->getRemoteId());
self::assertSame([
'title' => 'Title',
'description' => 'Description',
'managed_by' => 0,
'town' => 0,
], $entity->getData());
}
/**
* @test
*/
public function convertsJsonIdToGenericEntityWithRelations(): void
{
$jsonLD = [
'@id' => 'https://example.com/resources/018132452787-ngbe',
'thuecat:managedBy' => [
'@id' => 'https://example.com/resources/018132452787-xxxx',
],
'schema:containedInPlace' => [
[
'@id' => 'https://example.com/resources/043064193523-jcyt',
],
[
'@id' => 'https://example.com/resources/573211638937-gmqb',
],
],
'schema:name' => [
'@value' => 'Title',
],
'schema:description' => [
[
'@value' => 'Description',
],
],
];
$siteLanguage = $this->prophesize(SiteLanguage::class);
$language = $this->prophesize(LanguageHandling::class);
$language->getDefaultLanguage(10)->willReturn($siteLanguage);
$parser = $this->prophesize(Parser::class);
$parser->getManagerId($jsonLD)->willReturn('https://example.com/resources/018132452787-xxxx');
$parser->getContainedInPlaceIds($jsonLD)->willReturn([
'https://example.com/resources/043064193523-jcyt',
'https://example.com/resources/573211638937-gmqb',
]);
$parser->getId($jsonLD)->willReturn('https://example.com/resources/018132452787-ngbe');
$parser->getTitle($jsonLD, $siteLanguage->reveal())->willReturn('Title');
$parser->getDescription($jsonLD, $siteLanguage->reveal())->willReturn('Description');
$organisation = $this->prophesize(Organisation::class);
$organisation->getUid()->willReturn(10);
$organisationRepository = $this->prophesize(OrganisationRepository::class);
$organisationRepository->findOneByRemoteId('https://example.com/resources/018132452787-xxxx')
->willReturn($organisation->reveal());
$town = $this->prophesize(Town::class);
$town->getUid()->willReturn(20);
$townRepository = $this->prophesize(TownRepository::class);
$townRepository->findOneByRemoteIds([
'https://example.com/resources/043064193523-jcyt',
'https://example.com/resources/573211638937-gmqb',
])->willReturn($town->reveal());
$configuration = $this->prophesize(ImportConfiguration::class);
$configuration->getStoragePid()->willReturn(10);
$subject = new TouristInformation(
$parser->reveal(),
$language->reveal(),
$organisationRepository->reveal(),
$townRepository->reveal()
);
$entities = $subject->convert($jsonLD, $configuration->reveal());
self::assertInstanceOf(EntityCollection::class, $entities);
self::assertCount(1, $entities->getEntities());
$entity = $entities->getEntities()[0];
self::assertSame(10, $entity->getTypo3StoragePid());
self::assertSame('tx_thuecat_tourist_information', $entity->getTypo3DatabaseTableName());
self::assertSame('https://example.com/resources/018132452787-ngbe', $entity->getRemoteId());
self::assertSame([
'title' => 'Title',
'description' => 'Description',
'managed_by' => 10,
'town' => 20,
], $entity->getData());
}
}

View file

@ -1,216 +0,0 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import\Converter;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use WerkraumMedia\ThueCat\Domain\Import\Converter\Converter;
use WerkraumMedia\ThueCat\Domain\Import\Converter\Town;
use WerkraumMedia\ThueCat\Domain\Import\Importer\LanguageHandling;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser;
use WerkraumMedia\ThueCat\Domain\Import\Model\EntityCollection;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration;
use WerkraumMedia\ThueCat\Domain\Model\Backend\Organisation;
use WerkraumMedia\ThueCat\Domain\Repository\Backend\OrganisationRepository;
/**
* @covers \WerkraumMedia\ThueCat\Domain\Import\Converter\Town
*
* @uses \WerkraumMedia\ThueCat\Domain\Import\Model\EntityCollection
* @uses \WerkraumMedia\ThueCat\Domain\Import\Model\GenericEntity
*/
class TownTest extends TestCase
{
use ProphecyTrait;
/**
* @test
*/
public function instanceCanBeCreated(): void
{
$parser = $this->prophesize(Parser::class);
$language = $this->prophesize(LanguageHandling::class);
$organisationRepository = $this->prophesize(OrganisationRepository::class);
$subject = new Town(
$parser->reveal(),
$language->reveal(),
$organisationRepository->reveal()
);
self::assertInstanceOf(Town::class, $subject);
}
/**
* @test
*/
public function isInstanceOfConverter(): void
{
$parser = $this->prophesize(Parser::class);
$language = $this->prophesize(LanguageHandling::class);
$organisationRepository = $this->prophesize(OrganisationRepository::class);
$subject = new Town(
$parser->reveal(),
$language->reveal(),
$organisationRepository->reveal()
);
self::assertInstanceOf(Converter::class, $subject);
}
/**
* @test
*/
public function canConvertTouristMarketingCompany(): void
{
$parser = $this->prophesize(Parser::class);
$language = $this->prophesize(LanguageHandling::class);
$organisationRepository = $this->prophesize(OrganisationRepository::class);
$subject = new Town(
$parser->reveal(),
$language->reveal(),
$organisationRepository->reveal()
);
self::assertTrue($subject->canConvert([
'thuecat:Town',
]));
}
/**
* @test
*/
public function convertsJsonIdToGenericEntityWithoutOrganisation(): void
{
$jsonLD = [
'@id' => 'https://example.com/resources/018132452787-ngbe',
'thuecat:managedBy' => [
'@id' => 'https://example.com/resources/018132452787-xxxx',
],
'schema:name' => [
'@value' => 'Title',
],
'schema:description' => [
'@value' => 'Description',
],
];
$siteLanguage = $this->prophesize(SiteLanguage::class);
$language = $this->prophesize(LanguageHandling::class);
$language->getDefaultLanguage(10)->willReturn($siteLanguage->reveal());
$parser = $this->prophesize(Parser::class);
$parser->getManagerId($jsonLD)->willReturn('https://example.com/resources/018132452787-xxxx');
$parser->getId($jsonLD)->willReturn('https://example.com/resources/018132452787-ngbe');
$parser->getTitle($jsonLD, $siteLanguage->reveal())->willReturn('Title');
$parser->getDescription($jsonLD, $siteLanguage->reveal())->willReturn('Description');
$organisationRepository = $this->prophesize(OrganisationRepository::class);
$organisationRepository->findOneByRemoteId('https://example.com/resources/018132452787-xxxx')->willReturn(null);
$configuration = $this->prophesize(ImportConfiguration::class);
$configuration->getStoragePid()->willReturn(10);
$subject = new Town(
$parser->reveal(),
$language->reveal(),
$organisationRepository->reveal()
);
$entities = $subject->convert($jsonLD, $configuration->reveal());
self::assertInstanceOf(EntityCollection::class, $entities);
self::assertCount(1, $entities->getEntities());
$entity = $entities->getEntities()[0];
self::assertSame(10, $entity->getTypo3StoragePid());
self::assertSame('tx_thuecat_town', $entity->getTypo3DatabaseTableName());
self::assertSame('https://example.com/resources/018132452787-ngbe', $entity->getRemoteId());
self::assertSame([
'title' => 'Title',
'description' => 'Description',
'managed_by' => 0,
], $entity->getData());
}
/**
* @test
*/
public function convertsJsonIdToGenericEntityWithOrganisation(): void
{
$jsonLD = [
'@id' => 'https://example.com/resources/018132452787-ngbe',
'thuecat:managedBy' => [
'@id' => 'https://example.com/resources/018132452787-xxxx',
],
'schema:name' => [
'@value' => 'Title',
],
'schema:description' => [
'@value' => 'Description',
],
];
$siteLanguage = $this->prophesize(SiteLanguage::class);
$language = $this->prophesize(LanguageHandling::class);
$language->getDefaultLanguage(10)->willReturn($siteLanguage->reveal());
$parser = $this->prophesize(Parser::class);
$parser->getManagerId($jsonLD)->willReturn('https://example.com/resources/018132452787-xxxx');
$parser->getId($jsonLD)->willReturn('https://example.com/resources/018132452787-ngbe');
$parser->getTitle($jsonLD, $siteLanguage->reveal())->willReturn('Title');
$parser->getDescription($jsonLD, $siteLanguage->reveal())->willReturn('Description');
$organisation = $this->prophesize(Organisation::class);
$organisation->getUid()->willReturn(10);
$organisationRepository = $this->prophesize(OrganisationRepository::class);
$organisationRepository->findOneByRemoteId('https://example.com/resources/018132452787-xxxx')->willReturn($organisation->reveal());
$configuration = $this->prophesize(ImportConfiguration::class);
$configuration->getStoragePid()->willReturn(10);
$subject = new Town(
$parser->reveal(),
$language->reveal(),
$organisationRepository->reveal()
);
$entities = $subject->convert($jsonLD, $configuration->reveal());
self::assertInstanceOf(EntityCollection::class, $entities);
self::assertCount(1, $entities->getEntities());
$entity = $entities->getEntities()[0];
self::assertSame(10, $entity->getTypo3StoragePid());
self::assertSame('tx_thuecat_town', $entity->getTypo3DatabaseTableName());
self::assertSame('https://example.com/resources/018132452787-ngbe', $entity->getRemoteId());
self::assertSame([
'title' => 'Title',
'description' => 'Description',
'managed_by' => 10,
], $entity->getData());
}
}

View file

@ -1,103 +0,0 @@
<?php
namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import\Importer;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use TYPO3\CMS\Core\Site\Entity\Site;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use TYPO3\CMS\Core\Site\SiteFinder;
use WerkraumMedia\ThueCat\Domain\Import\Importer\LanguageHandling;
/**
* @covers \WerkraumMedia\ThueCat\Domain\Import\Importer\LanguageHandling
*/
class LanguageHandlingTest extends TestCase
{
use ProphecyTrait;
/**
* @test
*/
public function canBeCreated(): void
{
$siteFinder = $this->prophesize(SiteFinder::class);
$subject = new LanguageHandling(
$siteFinder->reveal()
);
self::assertInstanceOf(LanguageHandling::class, $subject);
}
/**
* @test
*/
public function returnsAllLanguagesForGivenPageUid(): void
{
$language = $this->prophesize(SiteLanguage::class);
$language->getTwoLetterIsoCode()->willReturn('de');
$language->getLanguageId()->willReturn(2);
$site = $this->prophesize(Site::class);
$site->getLanguages()->willReturn([$language->reveal()]);
$siteFinder = $this->prophesize(SiteFinder::class);
$siteFinder->getSiteByPageId(10)->willReturn($site->reveal());
$subject = new LanguageHandling(
$siteFinder->reveal()
);
$result = $subject->getLanguages(10);
self::assertCount(1, $result);
self::assertSame(2, $result[0]->getLanguageId());
self::assertSame('de', $result[0]->getTwoLetterIsoCode());
}
/**
* @test
*/
public function returnsDefaultLanguageForGivenPageUid(): void
{
$language = $this->prophesize(SiteLanguage::class);
$language->getTwoLetterIsoCode()->willReturn('de');
$language->getLanguageId()->willReturn(2);
$site = $this->prophesize(Site::class);
$site->getDefaultLanguage()->willReturn($language->reveal());
$siteFinder = $this->prophesize(SiteFinder::class);
$siteFinder->getSiteByPageId(10)->willReturn($site->reveal());
$subject = new LanguageHandling(
$siteFinder->reveal()
);
$result = $subject->getDefaultLanguage(10);
self::assertInstanceOf(SiteLanguage::class, $result);
self::assertSame(2, $result->getLanguageId());
self::assertSame('de', $result->getTwoLetterIsoCode());
}
}

View file

@ -1,272 +0,0 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use WerkraumMedia\ThueCat\Domain\Import\Converter\Converter;
use WerkraumMedia\ThueCat\Domain\Import\Converter\Registry as ConverterRegistry;
use WerkraumMedia\ThueCat\Domain\Import\Importer;
use WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData;
use WerkraumMedia\ThueCat\Domain\Import\Importer\SaveData;
use WerkraumMedia\ThueCat\Domain\Import\Model\EntityCollection;
use WerkraumMedia\ThueCat\Domain\Import\UrlProvider\Registry as UrlProviderRegistry;
use WerkraumMedia\ThueCat\Domain\Import\UrlProvider\UrlProvider;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLog;
use WerkraumMedia\ThueCat\Domain\Repository\Backend\ImportLogRepository;
/**
* @covers \WerkraumMedia\ThueCat\Domain\Import\Importer
* @uses \WerkraumMedia\ThueCat\Domain\Model\Backend\ImportLog
*/
class ImporterTest extends TestCase
{
use ProphecyTrait;
/**
* @test
*/
public function canBeCreated(): void
{
$urls = $this->prophesize(UrlProviderRegistry::class);
$converter = $this->prophesize(ConverterRegistry::class);
$importLogRepository = $this->prophesize(ImportLogRepository::class);
$fetchData = $this->prophesize(FetchData::class);
$saveData = $this->prophesize(SaveData::class);
$subject = new Importer(
$urls->reveal(),
$converter->reveal(),
$importLogRepository->reveal(),
$fetchData->reveal(),
$saveData->reveal()
);
self::assertInstanceOf(Importer::class, $subject);
}
/**
* @test
*/
public function importsNothingIfUrlProviderCouldNotBeResolved(): void
{
$urls = $this->prophesize(UrlProviderRegistry::class);
$converter = $this->prophesize(ConverterRegistry::class);
$importLogRepository = $this->prophesize(ImportLogRepository::class);
$fetchData = $this->prophesize(FetchData::class);
$saveData = $this->prophesize(SaveData::class);
$configuration = $this->prophesize(ImportConfiguration::class);
$urls->getProviderForConfiguration($configuration->reveal())->willReturn(null);
$fetchData->jsonLDFromUrl()->shouldNotBeCalled();
$saveData->import()->shouldNotBeCalled();
$subject = new Importer(
$urls->reveal(),
$converter->reveal(),
$importLogRepository->reveal(),
$fetchData->reveal(),
$saveData->reveal()
);
$result = $subject->importConfiguration($configuration->reveal());
self::assertInstanceOf(ImportLog::class, $result);
self::assertCount(0, $result->getEntries());
}
/**
* @test
*/
public function importsNothingIfNoUrlProviderIsGiven(): void
{
$urls = $this->prophesize(UrlProviderRegistry::class);
$urlProvider = $this->prophesize(UrlProvider::class);
$converter = $this->prophesize(ConverterRegistry::class);
$importLogRepository = $this->prophesize(ImportLogRepository::class);
$fetchData = $this->prophesize(FetchData::class);
$saveData = $this->prophesize(SaveData::class);
$configuration = $this->prophesize(ImportConfiguration::class);
$urls->getProviderForConfiguration($configuration->reveal())->willReturn($urlProvider->reveal());
$urlProvider->getUrls()->willReturn([]);
$fetchData->jsonLDFromUrl()->shouldNotBeCalled();
$saveData->import()->shouldNotBeCalled();
$subject = new Importer(
$urls->reveal(),
$converter->reveal(),
$importLogRepository->reveal(),
$fetchData->reveal(),
$saveData->reveal()
);
$subject->importConfiguration($configuration->reveal());
}
/**
* @test
*/
public function importsAllUrlsFromAllUrlProvider(): void
{
$urls = $this->prophesize(UrlProviderRegistry::class);
$urlProvider = $this->prophesize(UrlProvider::class);
$converter = $this->prophesize(ConverterRegistry::class);
$concreteConverter = $this->prophesize(Converter::class);
$importLogRepository = $this->prophesize(ImportLogRepository::class);
$fetchData = $this->prophesize(FetchData::class);
$saveData = $this->prophesize(SaveData::class);
$configuration = $this->prophesize(ImportConfiguration::class);
$entities1 = $this->prophesize(EntityCollection::class);
$entities2 = $this->prophesize(EntityCollection::class);
$urls->getProviderForConfiguration($configuration->reveal())->willReturn($urlProvider->reveal());
$urlProvider->getUrls()->willReturn([
'https://example.com/resources/34343-ex',
'https://example.com/resources/34344-es',
]);
$fetchData->jsonLDFromUrl('https://example.com/resources/34343-ex')->willReturn(['@graph' => [
[
'@id' => 'https://example.com/resources/34343-ex',
'@type' => [
'schema:Organization',
'thuecat:TouristMarketingCompany',
],
],
]]);
$fetchData->jsonLDFromUrl('https://example.com/resources/34344-es')->willReturn(['@graph' => [
[
'@id' => 'https://example.com/resources/34344-es',
'@type' => [
'schema:Organization',
'thuecat:TouristMarketingCompany',
],
],
]]);
$converter->getConverterBasedOnType([
'schema:Organization',
'thuecat:TouristMarketingCompany',
])->willReturn($concreteConverter->reveal());
$concreteConverter->convert(Argument::that(function (array $jsonEntity) {
return $jsonEntity['@id'] === 'https://example.com/resources/34343-ex';
}), $configuration->reveal())->willReturn($entities1->reveal());
$concreteConverter->convert(Argument::that(function (array $jsonEntity) {
return $jsonEntity['@id'] === 'https://example.com/resources/34344-es';
}), $configuration->reveal())->willReturn($entities2->reveal());
$saveData->import($entities1->reveal(), Argument::type(ImportLog::class))->shouldBeCalled();
$saveData->import($entities2->reveal(), Argument::type(ImportLog::class))->shouldBeCalled();
$subject = new Importer(
$urls->reveal(),
$converter->reveal(),
$importLogRepository->reveal(),
$fetchData->reveal(),
$saveData->reveal()
);
$subject->importConfiguration($configuration->reveal());
}
/**
* @test
*/
public function handlesMissingConverter(): void
{
$urls = $this->prophesize(UrlProviderRegistry::class);
$urlProvider = $this->prophesize(UrlProvider::class);
$converter = $this->prophesize(ConverterRegistry::class);
$concreteConverter = $this->prophesize(Converter::class);
$importLogRepository = $this->prophesize(ImportLogRepository::class);
$fetchData = $this->prophesize(FetchData::class);
$saveData = $this->prophesize(SaveData::class);
$configuration = $this->prophesize(ImportConfiguration::class);
$urls->getProviderForConfiguration($configuration->reveal())->willReturn($urlProvider->reveal());
$urlProvider->getUrls()->willReturn([
'https://example.com/resources/34343-ex',
]);
$fetchData->jsonLDFromUrl('https://example.com/resources/34343-ex')->willReturn(['@graph' => [
[
'@id' => 'https://example.com/resources/34343-ex',
'@type' => [
'schema:Organization',
'thuecat:TouristMarketingCompany',
],
],
]]);
$converter->getConverterBasedOnType([
'schema:Organization',
'thuecat:TouristMarketingCompany',
])->willReturn(null);
$saveData->import()->shouldNotBeCalled();
$subject = new Importer(
$urls->reveal(),
$converter->reveal(),
$importLogRepository->reveal(),
$fetchData->reveal(),
$saveData->reveal()
);
$subject->importConfiguration($configuration->reveal());
}
/**
* @test
*/
public function handlesEmptyResponse(): void
{
$urls = $this->prophesize(UrlProviderRegistry::class);
$urlProvider = $this->prophesize(UrlProvider::class);
$converter = $this->prophesize(ConverterRegistry::class);
$concreteConverter = $this->prophesize(Converter::class);
$importLogRepository = $this->prophesize(ImportLogRepository::class);
$fetchData = $this->prophesize(FetchData::class);
$saveData = $this->prophesize(SaveData::class);
$configuration = $this->prophesize(ImportConfiguration::class);
$urls->getProviderForConfiguration($configuration->reveal())->willReturn($urlProvider->reveal());
$urlProvider->getUrls()->willReturn([
'https://example.com/resources/34343-ex',
]);
$fetchData->jsonLDFromUrl('https://example.com/resources/34343-ex')->willReturn([]);
$converter->getConverterBasedOnType()->shouldNotBeCalled();
$subject = new Importer(
$urls->reveal(),
$converter->reveal(),
$importLogRepository->reveal(),
$fetchData->reveal(),
$saveData->reveal()
);
$subject->importConfiguration($configuration->reveal());
}
}

View file

@ -1,241 +0,0 @@
<?php
namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import\JsonLD\Parser;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use PHPUnit\Framework\TestCase;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Address;
/**
* @covers \WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Address
*/
class AddressTest extends TestCase
{
/**
* @test
*/
public function instanceCanBeCreated(): void
{
$subject = new Address(
);
self::assertInstanceOf(Address::class, $subject);
}
/**
* @test
*/
public function returnsFallback(): void
{
$subject = new Address(
);
$result = $subject->get([]);
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);
}
/**
* @test
*/
public function returnsFullAddress(): 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',
],
],
'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' => 'Waagegasse 8',
'zip' => '99084',
'city' => 'Erfurt',
'email' => 'altesynagoge@example.com',
'phone' => '+49 361 999999',
'fax' => '+49 361 999998',
'geo' => [
'latitude' => 50.978765,
'longitude' => 11.029133,
],
], $result);
}
}

View file

@ -1,100 +0,0 @@
<?php
namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import\JsonLD\Parser;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\GenericFields;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\LanguageValues;
/**
* @covers \WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\GenericFields
*/
class GenericFieldsTest extends TestCase
{
use ProphecyTrait;
/**
* @test
*/
public function canBeCreated(): void
{
$languageValues = $this->prophesize(LanguageValues::class);
$subject = new GenericFields(
$languageValues->reveal()
);
self::assertInstanceOf(GenericFields::class, $subject);
}
/**
* @test
*/
public function returnsTitle(): void
{
$siteLanguage = $this->prophesize(SiteLanguage::class);
$languageValues = $this->prophesize(LanguageValues::class);
$languageValues->getValueForLanguage([
'@value' => 'DE Title',
], $siteLanguage->reveal())->willReturn('DE Title');
$subject = new GenericFields(
$languageValues->reveal()
);
$result = $subject->getTitle([
'schema:name' => [
'@value' => 'DE Title',
],
], $siteLanguage->reveal());
self::assertSame('DE Title', $result);
}
/**
* @test
*/
public function returnsDescription(): void
{
$siteLanguage = $this->prophesize(SiteLanguage::class);
$languageValues = $this->prophesize(LanguageValues::class);
$languageValues->getValueForLanguage([
'@value' => 'DE Description',
], $siteLanguage->reveal())->willReturn('DE Description');
$subject = new GenericFields(
$languageValues->reveal()
);
$result = $subject->getDescription([
'schema:description' => [
'@value' => 'DE Description',
],
], $siteLanguage->reveal());
self::assertSame('DE Description', $result);
}
}

View file

@ -1,132 +0,0 @@
<?php
namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import\JsonLD\Parser;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\LanguageValues;
/**
* @covers \WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\LanguageValues
*/
class LanguageValuesTest extends TestCase
{
use ProphecyTrait;
/**
* @test
*/
public function canBeCreated(): void
{
$subject = new LanguageValues(
);
self::assertInstanceOf(LanguageValues::class, $subject);
}
/**
* @test
* @dataProvider setups
*/
public function returnsValue(array $jsonLD, string $language, string $expected): void
{
$siteLanguage = $this->prophesize(SiteLanguage::class);
$siteLanguage->getTwoLetterIsoCode()->willReturn($language);
$subject = new LanguageValues(
);
$result = $subject->getValueForLanguage($jsonLD, $siteLanguage->reveal());
self::assertSame($expected, $result);
}
public function setups(): array
{
return [
'has multiple lanugages, one matches' => [
'jsonLD' => [
[
'@language' => 'de',
'@value' => 'DE value',
],
[
'@language' => 'fr',
'@value' => 'FR value',
],
],
'language' => 'de',
'expected' => 'DE value',
],
'has multiple languages, none matches' => [
'jsonLD' => [
[
'@language' => 'de',
'@value' => 'DE value',
],
[
'@language' => 'fr',
'@value' => 'FR value',
],
],
'language' => 'en',
'expected' => '',
],
'has multiple languages, missing @language key' => [
'jsonLD' => [
[
'@value' => 'DE value',
],
[
'@value' => 'FR value',
],
],
'language' => 'en',
'expected' => '',
],
'has single language, that one matches' => [
'jsonLD' => [
'@language' => 'de',
'@value' => 'DE value',
],
'language' => 'de',
'expected' => 'DE value',
],
'has single language, but another is requested' => [
'jsonLD' => [
'@language' => 'de',
'@value' => 'DE value',
],
'language' => 'en',
'expected' => '',
],
'has single language, missing @language key' => [
'jsonLD' => [
'@value' => 'DE value',
],
'language' => '',
'expected' => '',
],
];
}
}

View file

@ -1,277 +0,0 @@
<?php
namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import\JsonLD\Parser;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData;
use WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData\InvalidResponseException;
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 returnsEmptyArrayOn404(): void
{
$fetchData = $this->prophesize(FetchData::class);
$fetchData->jsonLDFromUrl('https://thuecat.org/resources/dms_5099196')->willThrow(new InvalidResponseException());
$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([], $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);
}
}

View file

@ -1,439 +0,0 @@
<?php
namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import\JsonLD\Parser;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\GenericFields;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Offers;
/**
* @covers \WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Offers
*/
class OffersTest extends TestCase
{
use ProphecyTrait;
/**
* @test
*/
public function canBeCreated(): void
{
$genericFields = $this->prophesize(GenericFields::class);
$subject = new Offers(
$genericFields->reveal()
);
self::assertInstanceOf(Offers::class, $subject);
}
/**
* @test
*/
public function returnsEmptyArrayIfNoOfferExists(): void
{
$siteLanguage = $this->prophesize(SiteLanguage::class);
$genericFields = $this->prophesize(GenericFields::class);
$subject = new Offers(
$genericFields->reveal()
);
$result = $subject->get([], $siteLanguage->reveal());
self::assertSame([], $result);
}
/**
* @test
*/
public function returnsMultipleOfferWithMultiplePrices(): void
{
$jsonLD = [
'schema:makesOffer' => [
[
'@id' => 'genid-28b33237f71b41e3ad54a99e1da769b9-b5',
'@type' => [
0 => 'schema:Intangible',
1 => 'schema:Thing',
2 => 'schema:Offer',
],
'schema:description' => [
'@language' => 'de',
'@value' => 'Immer samstags, um 11:15 Uhr findet eine öffentliche Führung durch das Museum statt. Dauer etwa 90 Minuten',
],
'schema:name' => [
'@language' => 'de',
'@value' => 'Führungen',
],
'schema:offeredBy' => [
'@id' => 'https://thuecat.org/resources/165868194223-zmqf',
],
'schema:priceSpecification' => [
[
'@id' => 'genid-28b33237f71b41e3ad54a99e1da769b9-b6',
'@type' => [
0 => 'schema:Intangible',
1 => 'schema:StructuredValue',
2 => 'schema:PriceSpecification',
3 => 'schema:Thing',
],
'schema:name' => [
'@language' => 'de',
'@value' => 'Erwachsene',
],
'schema:price' => [
'@type' => 'schema:Number',
'@value' => '8',
],
'schema:priceCurrency' => [
'@type' => 'thuecat:Currency',
'@value' => 'thuecat:EUR',
],
'thuecat:calculationRule' => [
'@type' => 'thuecat:CalculationRule',
'@value' => 'thuecat:PerPerson',
],
],
[
'@id' => 'genid-28b33237f71b41e3ad54a99e1da769b9-b7',
'@type' => [
0 => 'schema:Intangible',
1 => 'schema:StructuredValue',
2 => 'schema:PriceSpecification',
3 => 'schema:Thing',
],
'schema:description' => [
'@language' => 'de',
'@value' => 'als ermäßigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt',
],
'schema:name' => [
'@language' => 'de',
'@value' => 'Ermäßigt',
],
'schema:price' => [
'@type' => 'schema:Number',
'@value' => '5',
],
'schema:priceCurrency' => [
'@type' => 'thuecat:Currency',
'@value' => 'thuecat:EUR',
],
'thuecat:calculationRule' => [
'@type' => 'thuecat:CalculationRule',
'@value' => 'thuecat:PerPerson',
],
],
],
'thuecat:offerType' => [
'@type' => 'thuecat:OfferType',
'@value' => 'thuecat:GuidedTourOffer',
],
],
[
'@id' => 'genid-28b33237f71b41e3ad54a99e1da769b9-b8',
'@type' => [
0 => 'schema:Intangible',
1 => 'schema:Thing',
2 => 'schema:Offer',
],
'schema:description' => [
'@language' => 'de',
'@value' => "Schulklassen und Kitagruppen im Rahmen des Unterrichts: Eintritt frei\nAn jedem ersten Dienstag im Monat: Eintritt frei",
],
'schema:name' => [
'@language' => 'de',
'@value' => 'Eintritt',
],
'schema:offeredBy' => [
'@id' => 'https://thuecat.org/resources/165868194223-zmqf',
],
'schema:priceSpecification' => [
[
'@id' => 'genid-28b33237f71b41e3ad54a99e1da769b9-b10',
'@type' => [
0 => 'schema:Intangible',
1 => 'schema:StructuredValue',
2 => 'schema:PriceSpecification',
3 => 'schema:Thing',
],
'schema:description' => [
'@language' => 'de',
'@value' => 'als ermäßigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt',
],
'schema:name' => [
'@language' => 'de',
'@value' => 'Ermäßigt',
],
'schema:price' => [
'@type' => 'schema:Number',
'@value' => '5',
],
'schema:priceCurrency' => [
'@type' => 'thuecat:Currency',
'@value' => 'thuecat:EUR',
],
'thuecat:calculationRule' => [
'@type' => 'thuecat:CalculationRule',
'@value' => 'thuecat:PerPerson',
],
],
[
'@id' => 'genid-28b33237f71b41e3ad54a99e1da769b9-b11',
'@type' => [
0 => 'schema:Intangible',
1 => 'schema:StructuredValue',
2 => 'schema:PriceSpecification',
3 => 'schema:Thing',
],
'schema:name' => [
'@language' => 'de',
'@value' => 'Familienkarte',
],
'schema:price' => [
'@type' => 'schema:Number',
'@value' => '17',
],
'schema:priceCurrency' => [
'@type' => 'thuecat:Currency',
'@value' => 'thuecat:EUR',
],
'thuecat:calculationRule' => [
'@type' => 'thuecat:CalculationRule',
'@value' => 'thuecat:PerGroup',
],
],
],
'thuecat:offerType' => [
'@type' => 'thuecat:OfferType',
'@value' => 'thuecat:EntryOffer',
],
],
],
];
$siteLanguage = $this->prophesize(SiteLanguage::class);
$genericFields = $this->prophesize(GenericFields::class);
// Offer 1
$genericFields->getTitle(
$jsonLD['schema:makesOffer'][0],
$siteLanguage->reveal()
)->willReturn('Führungen');
$genericFields->getDescription(
$jsonLD['schema:makesOffer'][0],
$siteLanguage->reveal()
)->willReturn('Immer samstags, um 11:15 Uhr findet eine öffentliche Führung durch das Museum statt. Dauer etwa 90 Minuten');
$genericFields->getTitle(
$jsonLD['schema:makesOffer'][0]['schema:priceSpecification'][0],
$siteLanguage->reveal()
)->willReturn('Erwachsene');
$genericFields->getDescription(
$jsonLD['schema:makesOffer'][0]['schema:priceSpecification'][0],
$siteLanguage->reveal()
)->willReturn('');
$genericFields->getTitle(
$jsonLD['schema:makesOffer'][0]['schema:priceSpecification'][1],
$siteLanguage->reveal()
)->willReturn('Ermäßigt');
$genericFields->getDescription(
$jsonLD['schema:makesOffer'][0]['schema:priceSpecification'][1],
$siteLanguage->reveal()
)->willReturn('als ermäßigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt');
// Offer2
$genericFields->getTitle(
$jsonLD['schema:makesOffer'][1],
$siteLanguage->reveal()
)->willReturn('Eintritt');
$genericFields->getDescription(
$jsonLD['schema:makesOffer'][1],
$siteLanguage->reveal()
)->willReturn("Schulklassen und Kitagruppen im Rahmen des Unterrichts: Eintritt frei\nAn jedem ersten Dienstag im Monat: Eintritt frei");
$genericFields->getTitle(
$jsonLD['schema:makesOffer'][1]['schema:priceSpecification'][0],
$siteLanguage->reveal()
)->willReturn('Ermäßigt');
$genericFields->getDescription(
$jsonLD['schema:makesOffer'][1]['schema:priceSpecification'][0],
$siteLanguage->reveal()
)->willReturn('als ermäßigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt');
$genericFields->getTitle(
$jsonLD['schema:makesOffer'][1]['schema:priceSpecification'][1],
$siteLanguage->reveal()
)->willReturn('Familienkarte');
$genericFields->getDescription(
$jsonLD['schema:makesOffer'][1]['schema:priceSpecification'][1],
$siteLanguage->reveal()
)->willReturn('');
$subject = new Offers(
$genericFields->reveal()
);
$result = $subject->get($jsonLD, $siteLanguage->reveal());
self::assertSame([
[
'title' => 'Führungen',
'description' => 'Immer samstags, um 11:15 Uhr findet eine öffentliche Führung durch das Museum statt. Dauer etwa 90 Minuten',
'prices' => [
[
'title' => 'Erwachsene',
'description' => '',
'price' => 8.0,
'currency' => 'EUR',
'rule' => 'PerPerson',
],
[
'title' => 'Ermäßigt',
'description' => 'als ermäßigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt',
'price' => 5.0,
'currency' => 'EUR',
'rule' => 'PerPerson',
],
],
],
[
'title' => 'Eintritt',
'description' => "Schulklassen und Kitagruppen im Rahmen des Unterrichts: Eintritt frei\nAn jedem ersten Dienstag im Monat: Eintritt frei",
'prices' => [
[
'title' => 'Ermäßigt',
'description' => 'als ermäßigt gelten schulpflichtige Kinder, Auszubildende, Studierende, Rentner/-innen, Menschen mit Behinderungen, Inhaber Sozialausweis der Landeshauptstadt Erfurt',
'price' => 5.0,
'currency' => 'EUR',
'rule' => 'PerPerson',
],
[
'title' => 'Familienkarte',
'description' => '',
'price' => 17.0,
'currency' => 'EUR',
'rule' => 'PerGroup',
],
],
],
], $result);
}
/**
* @test
*/
public function returnsSingleOfferWithSinglePrice(): void
{
$jsonLD = [
'schema:makesOffer' => [
'@id' => 'genid-28b33237f71b41e3ad54a99e1da769b9-b5',
'@type' => [
0 => 'schema:Intangible',
1 => 'schema:Thing',
2 => 'schema:Offer',
],
'schema:description' => [
'@language' => 'de',
'@value' => 'Immer samstags, um 11:15 Uhr findet eine öffentliche Führung durch das Museum statt. Dauer etwa 90 Minuten',
],
'schema:name' => [
'@language' => 'de',
'@value' => 'Führungen',
],
'schema:offeredBy' => [
'@id' => 'https://thuecat.org/resources/165868194223-zmqf',
],
'schema:priceSpecification' => [
'@id' => 'genid-28b33237f71b41e3ad54a99e1da769b9-b6',
'@type' => [
0 => 'schema:Intangible',
1 => 'schema:StructuredValue',
2 => 'schema:PriceSpecification',
3 => 'schema:Thing',
],
'schema:name' => [
'@language' => 'de',
'@value' => 'Erwachsene',
],
'schema:price' => [
'@type' => 'schema:Number',
'@value' => '8',
],
'schema:priceCurrency' => [
'@type' => 'thuecat:Currency',
'@value' => 'thuecat:EUR',
],
'thuecat:calculationRule' => [
'@type' => 'thuecat:CalculationRule',
'@value' => 'thuecat:PerPerson',
],
],
'thuecat:offerType' => [
'@type' => 'thuecat:OfferType',
'@value' => 'thuecat:GuidedTourOffer',
],
],
];
$siteLanguage = $this->prophesize(SiteLanguage::class);
$genericFields = $this->prophesize(GenericFields::class);
$genericFields->getTitle(
$jsonLD['schema:makesOffer'],
$siteLanguage->reveal()
)->willReturn('Führungen');
$genericFields->getDescription(
$jsonLD['schema:makesOffer'],
$siteLanguage->reveal()
)->willReturn('Immer samstags, um 11:15 Uhr findet eine öffentliche Führung durch das Museum statt. Dauer etwa 90 Minuten');
$genericFields->getTitle(
$jsonLD['schema:makesOffer']['schema:priceSpecification'],
$siteLanguage->reveal()
)->willReturn('Erwachsene');
$genericFields->getDescription(
$jsonLD['schema:makesOffer']['schema:priceSpecification'],
$siteLanguage->reveal()
)->willReturn('');
$subject = new Offers(
$genericFields->reveal()
);
$result = $subject->get($jsonLD, $siteLanguage->reveal());
self::assertSame([
[
'title' => 'Führungen',
'description' => 'Immer samstags, um 11:15 Uhr findet eine öffentliche Führung durch das Museum statt. Dauer etwa 90 Minuten',
'prices' => [
[
'title' => 'Erwachsene',
'description' => '',
'price' => 8.0,
'currency' => 'EUR',
'rule' => 'PerPerson',
],
],
],
], $result);
}
}

View file

@ -1,310 +0,0 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import\JsonLD\Parser;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use PHPUnit\Framework\TestCase;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\OpeningHours;
/**
* @covers \WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\OpeningHours
*/
class OpeningHoursTest extends TestCase
{
/**
* @test
*/
public function canBeCreated(): void
{
$subject = new OpeningHours();
self::assertInstanceOf(OpeningHours::class, $subject);
}
/**
* @test
*/
public function returnsEmptyArrayIfOpeningHoursAreMissing(): void
{
$subject = new OpeningHours();
$result = $subject->get([
]);
self::assertSame([], $result);
}
/**
* @test
*/
public function returnsSingleOpeningHourWrappedInArray(): void
{
$subject = new OpeningHours();
$result = $subject->get([
'schema:openingHoursSpecification' => [
'@id' => 'genid-28b33237f71b41e3ad54a99e1da769b9-b13',
'schema:opens' => [
'@type' => 'schema:Time',
'@value' => '10:00:00',
],
'schema:closes' => [
'@type' => 'schema:Time',
'@value' => '18:00:00',
],
'schema:validFrom' => [
'@type' => 'schema:Date',
'@value' => '2021-03-01',
],
'schema:validThrough' => [
'@type' => 'schema:Date',
'@value' => '2021-12-31',
],
'schema:dayOfWeek' => [
0 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Saturday',
],
1 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Sunday',
],
2 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Friday',
],
3 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Thursday',
],
4 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Tuesday',
],
5 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Wednesday',
],
],
],
]);
self::assertCount(1, $result);
self::assertSame('10:00:00', $result[0]['opens']);
self::assertSame('18:00:00', $result[0]['closes']);
self::assertSame([
'Friday',
'Saturday',
'Sunday',
'Thursday',
'Tuesday',
'Wednesday',
], $result[0]['daysOfWeek']);
self::assertInstanceOf(\DateTimeImmutable::class, $result[0]['from']);
self::assertSame('2021-03-01 00:00:00', $result[0]['from']->format('Y-m-d H:i:s'));
self::assertInstanceOf(\DateTimeImmutable::class, $result[0]['through']);
self::assertSame('2021-12-31 00:00:00', $result[0]['through']->format('Y-m-d H:i:s'));
}
/**
* @test
*/
public function returnsSingleWeekDay(): void
{
$subject = new OpeningHours();
$result = $subject->get([
'schema:openingHoursSpecification' => [
'@id' => 'genid-28b33237f71b41e3ad54a99e1da769b9-b13',
'schema:dayOfWeek' => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Saturday',
],
],
]);
self::assertCount(1, $result);
self::assertSame([
'Saturday',
], $result[0]['daysOfWeek']);
}
/**
* @test
*/
public function returnsMultipleOpeningHours(): void
{
$subject = new OpeningHours();
$result = $subject->get([
'schema:openingHoursSpecification' => [
[
'@id' => 'genid-28b33237f71b41e3ad54a99e1da769b9-b13',
'schema:opens' => [
'@type' => 'schema:Time',
'@value' => '10:00:00',
],
'schema:closes' => [
'@type' => 'schema:Time',
'@value' => '18:00:00',
],
'schema:validFrom' => [
'@type' => 'schema:Date',
'@value' => '2021-03-01',
],
'schema:validThrough' => [
'@type' => 'schema:Date',
'@value' => '2021-12-31',
],
'schema:dayOfWeek' => [
0 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Saturday',
],
1 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Sunday',
],
2 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Friday',
],
3 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Thursday',
],
4 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Tuesday',
],
5 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Wednesday',
],
],
],
[
'@id' => 'genid-28b33237f71b41e3ad54a99e1da769b9-b13',
'schema:opens' => [
'@type' => 'schema:Time',
'@value' => '09:00:00',
],
'schema:closes' => [
'@type' => 'schema:Time',
'@value' => '17:00:00',
],
'schema:validFrom' => [
'@type' => 'schema:Date',
'@value' => '2022-03-01',
],
'schema:validThrough' => [
'@type' => 'schema:Date',
'@value' => '2022-12-31',
],
'schema:dayOfWeek' => [
0 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Saturday',
],
1 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Sunday',
],
2 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Friday',
],
3 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Thursday',
],
4 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Tuesday',
],
5 => [
'@type' => 'schema:DayOfWeek',
'@value' => 'schema:Wednesday',
],
],
],
],
]);
self::assertCount(2, $result);
self::assertSame('10:00:00', $result[0]['opens']);
self::assertSame('18:00:00', $result[0]['closes']);
self::assertSame([
'Friday',
'Saturday',
'Sunday',
'Thursday',
'Tuesday',
'Wednesday',
], $result[0]['daysOfWeek']);
self::assertInstanceOf(\DateTimeImmutable::class, $result[0]['from']);
self::assertSame('2021-03-01 00:00:00', $result[0]['from']->format('Y-m-d H:i:s'));
self::assertInstanceOf(\DateTimeImmutable::class, $result[0]['through']);
self::assertSame('2021-12-31 00:00:00', $result[0]['through']->format('Y-m-d H:i:s'));
self::assertSame('09:00:00', $result[1]['opens']);
self::assertSame('17:00:00', $result[1]['closes']);
self::assertSame([
'Friday',
'Saturday',
'Sunday',
'Thursday',
'Tuesday',
'Wednesday',
], $result[1]['daysOfWeek']);
self::assertInstanceOf(\DateTimeImmutable::class, $result[1]['from']);
self::assertSame('2022-03-01 00:00:00', $result[1]['from']->format('Y-m-d H:i:s'));
self::assertInstanceOf(\DateTimeImmutable::class, $result[1]['through']);
self::assertSame('2022-12-31 00:00:00', $result[1]['through']->format('Y-m-d H:i:s'));
}
/**
* @test
*/
public function returnsProperDefaultsOnMissingValues(): void
{
$subject = new OpeningHours();
$result = $subject->get([
'schema:openingHoursSpecification' => [
'@id' => 'genid-28b33237f71b41e3ad54a99e1da769b9-b13',
],
]);
self::assertCount(1, $result);
self::assertSame('', $result[0]['opens']);
self::assertSame('', $result[0]['closes']);
self::assertSame([], $result[0]['daysOfWeek']);
self::assertNull($result[0]['from']);
self::assertNull($result[0]['through']);
}
}

View file

@ -1,402 +0,0 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Tests\Unit\Domain\Import\JsonLD;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Address;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\GenericFields;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Media;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\OpeningHours;
/**
* @covers \WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser
*/
class ParserTest extends TestCase
{
use ProphecyTrait;
/**
* @test
*/
public function canBeCreated(): void
{
$genericFields = $this->prophesize(GenericFields::class);
$openingHours = $this->prophesize(OpeningHours::class);
$address = $this->prophesize(Address::class);
$media = $this->prophesize(Media::class);
$subject = new Parser(
$genericFields->reveal(),
$openingHours->reveal(),
$address->reveal(),
$media->reveal()
);
self::assertInstanceOf(Parser::class, $subject);
}
/**
* @test
*/
public function returnsId(): void
{
$genericFields = $this->prophesize(GenericFields::class);
$openingHours = $this->prophesize(OpeningHours::class);
$address = $this->prophesize(Address::class);
$media = $this->prophesize(Media::class);
$subject = new Parser(
$genericFields->reveal(),
$openingHours->reveal(),
$address->reveal(),
$media->reveal()
);
$result = $subject->getId([
'@id' => 'https://example.com/resources/165868194223-id',
]);
self::assertSame('https://example.com/resources/165868194223-id', $result);
}
/**
* @test
*/
public function returnsTitle(): void
{
$jsonLD = [
'schema:name' => [
'@language' => 'de',
'@value' => 'Erfurt',
],
];
$siteLanguage = $this->prophesize(SiteLanguage::class);
$genericFields = $this->prophesize(GenericFields::class);
$genericFields->getTitle($jsonLD, $siteLanguage->reveal())->willReturn('Erfurt');
$openingHours = $this->prophesize(OpeningHours::class);
$address = $this->prophesize(Address::class);
$media = $this->prophesize(Media::class);
$subject = new Parser(
$genericFields->reveal(),
$openingHours->reveal(),
$address->reveal(),
$media->reveal()
);
$result = $subject->getTitle($jsonLD, $siteLanguage->reveal());
self::assertSame('Erfurt', $result);
}
/**
* @test
*/
public function returnsDescription(): void
{
$jsonLD = [
'schema:description' => [
'@language' => 'de',
'@value' => 'Erfurt',
],
];
$siteLanguage = $this->prophesize(SiteLanguage::class);
$genericFields = $this->prophesize(GenericFields::class);
$genericFields->getDescription($jsonLD, $siteLanguage->reveal())->willReturn('Erfurt');
$openingHours = $this->prophesize(OpeningHours::class);
$address = $this->prophesize(Address::class);
$media = $this->prophesize(Media::class);
$subject = new Parser(
$genericFields->reveal(),
$openingHours->reveal(),
$address->reveal(),
$media->reveal()
);
$result = $subject->getDescription($jsonLD, $siteLanguage->reveal());
self::assertSame('Erfurt', $result);
}
/**
* @test
*/
public function returnsManagerId(): void
{
$genericFields = $this->prophesize(GenericFields::class);
$openingHours = $this->prophesize(OpeningHours::class);
$address = $this->prophesize(Address::class);
$media = $this->prophesize(Media::class);
$subject = new Parser(
$genericFields->reveal(),
$openingHours->reveal(),
$address->reveal(),
$media->reveal()
);
$result = $subject->getManagerId([
'thuecat:contentResponsible' => [
'@id' => 'https://example.com/resources/165868194223-manager',
],
]);
self::assertSame('https://example.com/resources/165868194223-manager', $result);
}
/**
* @test
*/
public function returnsContainedInPlaceIdsForMultipleEntries(): void
{
$genericFields = $this->prophesize(GenericFields::class);
$openingHours = $this->prophesize(OpeningHours::class);
$address = $this->prophesize(Address::class);
$media = $this->prophesize(Media::class);
$subject = new Parser(
$genericFields->reveal(),
$openingHours->reveal(),
$address->reveal(),
$media->reveal()
);
$result = $subject->getContainedInPlaceIds([
'schema:containedInPlace' => [
['@id' => 'https://thuecat.org/resources/043064193523-jcyt'],
['@id' => 'https://thuecat.org/resources/349986440346-kbkf'],
['@id' => 'https://thuecat.org/resources/794900260253-wjab'],
['@id' => 'https://thuecat.org/resources/476888881990-xpwq'],
['@id' => 'https://thuecat.org/resources/573211638937-gmqb'],
],
]);
self::assertSame([
'https://thuecat.org/resources/043064193523-jcyt',
'https://thuecat.org/resources/349986440346-kbkf',
'https://thuecat.org/resources/794900260253-wjab',
'https://thuecat.org/resources/476888881990-xpwq',
'https://thuecat.org/resources/573211638937-gmqb',
], $result);
}
/**
* @test
*/
public function returnsContainedInPlaceIdsForNoEntry(): void
{
$genericFields = $this->prophesize(GenericFields::class);
$openingHours = $this->prophesize(OpeningHours::class);
$address = $this->prophesize(Address::class);
$media = $this->prophesize(Media::class);
$subject = new Parser(
$genericFields->reveal(),
$openingHours->reveal(),
$address->reveal(),
$media->reveal()
);
$result = $subject->getContainedInPlaceIds([]);
self::assertSame([], $result);
}
/**
* @test
*/
public function returnsContainedInPlaceIdsForSingleEntry(): void
{
$genericFields = $this->prophesize(GenericFields::class);
$openingHours = $this->prophesize(OpeningHours::class);
$address = $this->prophesize(Address::class);
$media = $this->prophesize(Media::class);
$subject = new Parser(
$genericFields->reveal(),
$openingHours->reveal(),
$address->reveal(),
$media->reveal()
);
$result = $subject->getContainedInPlaceIds([
'schema:containedInPlace' => [
'@id' => 'https://thuecat.org/resources/043064193523-jcyt',
],
]);
self::assertSame([
'https://thuecat.org/resources/043064193523-jcyt',
], $result);
}
/**
* @test
*/
public function returnsOpeningHours(): void
{
$jsonLD = [
'schema:openingHoursSpecification' => [
'@id' => 'genid-28b33237f71b41e3ad54a99e1da769b9-b13',
'schema:opens' => [
'@type' => 'schema:Time',
'@value' => '10:00:00',
],
],
];
$generatedOpeningHours = [
'opens' => '10:00:00',
'closes' => '',
'from' => null,
'through' => null,
'daysOfWeek' => [],
];
$genericFields = $this->prophesize(GenericFields::class);
$openingHours = $this->prophesize(OpeningHours::class);
$openingHours->get($jsonLD)->willReturn($generatedOpeningHours);
$address = $this->prophesize(Address::class);
$media = $this->prophesize(Media::class);
$subject = new Parser(
$genericFields->reveal(),
$openingHours->reveal(),
$address->reveal(),
$media->reveal()
);
$result = $subject->getOpeningHours($jsonLD);
self::assertSame($generatedOpeningHours, $result);
}
/**
* @test
*/
public function returnsAddress(): void
{
$jsonLD = [
'schema:address' => [
'@id' => 'genid-28b33237f71b41e3ad54a99e1da769b9-b0',
'schema:addressLocality' => [
'@language' => 'de',
'@value' => 'Erfurt',
],
],
];
$generatedAddress = [
'street' => '',
'zip' => '',
'city' => 'Erfurt',
'email' => '',
'phone' => '',
'fax' => '',
];
$genericFields = $this->prophesize(GenericFields::class);
$openingHours = $this->prophesize(OpeningHours::class);
$address = $this->prophesize(Address::class);
$address->get($jsonLD)->willReturn($generatedAddress);
$media = $this->prophesize(Media::class);
$subject = new Parser(
$genericFields->reveal(),
$openingHours->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',
],
],
];
$genericFields = $this->prophesize(GenericFields::class);
$openingHours = $this->prophesize(OpeningHours::class);
$address = $this->prophesize(Address::class);
$media = $this->prophesize(Media::class);
$media->get($jsonLD)->willReturn($generatedMedia);
$subject = new Parser(
$genericFields->reveal(),
$openingHours->reveal(),
$address->reveal(),
$media->reveal()
);
$result = $subject->getMedia($jsonLD);
self::assertSame($generatedMedia, $result);
}
}

View file

@ -29,11 +29,15 @@
"require": {
"php": "^7.3",
"ext-json": "*",
"ext-mbstring": "*",
"psr/http-client": "^1.0",
"psr/http-factory": "^1.0",
"psr/http-message": "^1.0",
"symfony/console": "^5.2",
"symfony/dependency-injection": "^5.2",
"symfony/property-access": "^5.3",
"symfony/property-info": "^5.3",
"symfony/serializer": "^5.3",
"typo3/cms-backend": "^10.4",
"typo3/cms-core": "^10.4",
"typo3/cms-extbase": "^10.4",
@ -47,6 +51,7 @@
"phpspec/prophecy-phpunit": "^2.0",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^0.12.71",
"phpstan/phpstan-phpunit": "^0.12.21",
"phpunit/phpunit": "^9.5",
"symplify/easy-coding-standard": "^9.0",
"typo3/cms-fluid-styled-content": "^10.4",

View file

@ -1,5 +1,10 @@
parameters:
ignoreErrors:
-
message: "#^Parameter \\#1 \\$function of function call_user_func expects callable\\(\\)\\: mixed, array\\(string\\|null, 'getSupportedTypes'\\) given\\.$#"
count: 1
path: Classes/DependencyInjection/EntityPass.php
-
message: "#^Cannot call method fetchColumn\\(\\) on Doctrine\\\\DBAL\\\\Driver\\\\ResultStatement\\|int\\.$#"
count: 2
@ -16,7 +21,7 @@ parameters:
path: Classes/Domain/Repository/Backend/TownRepository.php
-
message: "#^Method WerkraumMedia\\\\ThueCat\\\\Domain\\\\Repository\\\\Backend\\\\TownRepository\\:\\:findOneByRemoteIds\\(\\) should return WerkraumMedia\\\\ThueCat\\\\Domain\\\\Model\\\\Backend\\\\Town\\|null but returns object\\.$#"
message: "#^Method WerkraumMedia\\\\ThueCat\\\\Domain\\\\Repository\\\\Backend\\\\TownRepository\\:\\:findOneByEntity\\(\\) should return WerkraumMedia\\\\ThueCat\\\\Domain\\\\Model\\\\Backend\\\\Town\\|null but returns object\\.$#"
count: 1
path: Classes/Domain/Repository/Backend/TownRepository.php