Add prices to tourist attraction

Import prices, show them in records and make them accessible in
frontend.
This commit is contained in:
Daniel Siepmann 2021-02-18 14:54:00 +01:00
parent 775db67efa
commit 442a6842ec
23 changed files with 1205 additions and 302 deletions

View file

@ -26,6 +26,7 @@ namespace WerkraumMedia\ThueCat\Domain\Import\Converter;
use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\GeneralUtility;
use WerkraumMedia\ThueCat\Domain\Import\Importer\LanguageHandling; use WerkraumMedia\ThueCat\Domain\Import\Importer\LanguageHandling;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser; 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\EntityCollection;
use WerkraumMedia\ThueCat\Domain\Import\Model\GenericEntity; use WerkraumMedia\ThueCat\Domain\Import\Model\GenericEntity;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration; use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration;
@ -35,17 +36,20 @@ use WerkraumMedia\ThueCat\Domain\Repository\Backend\TownRepository;
class TouristAttraction implements Converter class TouristAttraction implements Converter
{ {
private Parser $parser; private Parser $parser;
private Offers $parserForOffers;
private LanguageHandling $language; private LanguageHandling $language;
private OrganisationRepository $organisationRepository; private OrganisationRepository $organisationRepository;
private TownRepository $townRepository; private TownRepository $townRepository;
public function __construct( public function __construct(
Parser $parser, Parser $parser,
Offers $parserForOffers,
LanguageHandling $language, LanguageHandling $language,
OrganisationRepository $organisationRepository, OrganisationRepository $organisationRepository,
TownRepository $townRepository TownRepository $townRepository
) { ) {
$this->parser = $parser; $this->parser = $parser;
$this->parserForOffers = $parserForOffers;
$this->language = $language; $this->language = $language;
$this->organisationRepository = $organisationRepository; $this->organisationRepository = $organisationRepository;
$this->townRepository = $townRepository; $this->townRepository = $townRepository;
@ -77,6 +81,7 @@ class TouristAttraction implements Converter
'opening_hours' => json_encode($this->parser->getOpeningHours($jsonLD)), 'opening_hours' => json_encode($this->parser->getOpeningHours($jsonLD)),
'address' => json_encode($this->parser->getAddress($jsonLD)), 'address' => json_encode($this->parser->getAddress($jsonLD)),
'media' => json_encode($this->parser->getMedia($jsonLD)), 'media' => json_encode($this->parser->getMedia($jsonLD)),
'offers' => json_encode($this->parserForOffers->get($jsonLD, $language)),
] ]
); );
$entities->add($entity); $entities->add($entity);

View file

@ -24,20 +24,24 @@ namespace WerkraumMedia\ThueCat\Domain\Import\JsonLD;
*/ */
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Address; 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\Media;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\OpeningHours; use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\OpeningHours;
class Parser class Parser
{ {
private GenericFields $genericFields;
private OpeningHours $openingHours; private OpeningHours $openingHours;
private Address $address; private Address $address;
private Media $media; private Media $media;
public function __construct( public function __construct(
GenericFields $genericFields,
OpeningHours $openingHours, OpeningHours $openingHours,
Address $address, Address $address,
Media $media Media $media
) { ) {
$this->genericFields = $genericFields;
$this->openingHours = $openingHours; $this->openingHours = $openingHours;
$this->address = $address; $this->address = $address;
$this->media = $media; $this->media = $media;
@ -50,12 +54,12 @@ class Parser
public function getTitle(array $jsonLD, string $language = ''): string public function getTitle(array $jsonLD, string $language = ''): string
{ {
return $this->getValueForLanguage($jsonLD['schema:name'], $language); return $this->genericFields->getTitle($jsonLD, $language);
} }
public function getDescription(array $jsonLD, string $language = ''): string public function getDescription(array $jsonLD, string $language = ''): string
{ {
return $this->getValueForLanguage($jsonLD['schema:description'], $language); return $this->genericFields->getDescription($jsonLD, $language);
} }
public function getManagerId(array $jsonLD): string public function getManagerId(array $jsonLD): string
@ -108,6 +112,7 @@ class Parser
$languages = array_map(function (array $language) { $languages = array_map(function (array $language) {
$language = $language['@value']; $language = $language['@value'];
// TODO: Make configurable / easier to extend
if ($language === 'thuecat:German') { if ($language === 'thuecat:German') {
return 'de'; return 'de';
} }
@ -123,37 +128,4 @@ class Parser
return $languages; return $languages;
} }
private function getValueForLanguage(
array $property,
string $language
): string {
if (
$this->doesLanguageMatch($property, $language)
&& isset($property['@value'])
) {
return $property['@value'];
}
foreach ($property as $languageEntry) {
if (
is_array($languageEntry)
&& $this->doesLanguageMatch($languageEntry, $language)
) {
return $languageEntry['@value'];
}
}
return '';
}
private function doesLanguageMatch(array $property, string $language): bool
{
return isset($property['@language'])
&& (
$property['@language'] === $language
|| $language === ''
)
;
}
} }

View file

@ -0,0 +1,43 @@
<?php
namespace WerkraumMedia\ThueCat\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.
*/
class GenericFields
{
private LanguageValues $languageValues;
public function __construct(
LanguageValues $languageValues
) {
$this->languageValues = $languageValues;
}
public function getTitle(array $jsonLD, string $language = ''): string
{
return $this->languageValues->getValueForLanguage($jsonLD['schema:name'] ?? [], $language);
}
public function getDescription(array $jsonLD, string $language = ''): string
{
return $this->languageValues->getValueForLanguage($jsonLD['schema:description'] ?? [], $language);
}
}

View file

@ -0,0 +1,60 @@
<?php
namespace WerkraumMedia\ThueCat\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.
*/
class LanguageValues
{
public function getValueForLanguage(
array $property,
string $language
): string {
if (
$this->doesLanguageMatch($property, $language)
&& isset($property['@value'])
) {
return $property['@value'];
}
foreach ($property as $languageEntry) {
if (
is_array($languageEntry)
&& $this->doesLanguageMatch($languageEntry, $language)
) {
return $languageEntry['@value'];
}
}
return '';
}
private function doesLanguageMatch(
array $property,
string $language
): bool {
return isset($property['@language'])
&& (
$property['@language'] === $language
|| $language === ''
)
;
}
}

View file

@ -0,0 +1,103 @@
<?php
namespace WerkraumMedia\ThueCat\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.
*/
class Offers
{
private GenericFields $genericFields;
public function __construct(
GenericFields $genericFields
) {
$this->genericFields = $genericFields;
}
public function get(array $jsonLD, string $language): array
{
$offers = [];
$jsonLDOffers = $jsonLD['schema:makesOffer'] ?? [];
foreach ($jsonLDOffers as $jsonLDOffer) {
$offer = $this->getOffer($jsonLDOffer, $language);
if ($offer !== []) {
$offers[] = $offer;
}
}
return $offers;
}
private function getOffer(array $jsonLD, string $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, string $language): array
{
$prices = [];
$jsonLDPrices = $jsonLD['schema:priceSpecification'] ?? [];
foreach ($jsonLDPrices as $jsonLDPrice) {
$price = $this->getPrice($jsonLDPrice, $language);
if ($price !== []) {
$prices[] = $price;
}
}
return $prices;
}
private function getPrice(array $jsonLD, string $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

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

View file

@ -0,0 +1,75 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Model\Frontend;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use TYPO3\CMS\Core\Type\TypeInterface;
/**
* @implements \Iterator<int, Offer>
*/
class Offers implements TypeInterface, \Iterator
{
private string $serialized = '';
private array $array = [];
private int $position = 0;
public function __construct(string $serialized)
{
$this->serialized = $serialized;
$this->array = array_map(
[Offer::class, 'createFromArray'],
json_decode($serialized, true)
);
}
public function __toString(): string
{
return $this->serialized;
}
public function current(): Offer
{
return $this->array[$this->position];
}
public function next(): void
{
++$this->position;
}
public function key(): int
{
return $this->position;
}
public function valid(): bool
{
return isset($this->array[$this->position]);
}
public function rewind(): void
{
$this->position = 0;
}
}

View file

@ -0,0 +1,83 @@
<?php
declare(strict_types=1);
namespace WerkraumMedia\ThueCat\Domain\Model\Frontend;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
class Price
{
private string $title;
private string $description;
private float $price;
private string $currency;
private string $rule;
private function __construct(
string $title,
string $description,
float $price,
string $currency,
string $rule
) {
$this->title = $title;
$this->description = $description;
$this->price = $price;
$this->currency = $currency;
$this->rule = $rule;
}
public static function createFromArray(array $rawData): self
{
return new self(
$rawData['title'],
$rawData['description'],
$rawData['price'],
$rawData['currency'],
$rawData['rule']
);
}
public function getTitle(): string
{
return $this->title;
}
public function getDescription(): string
{
return $this->description;
}
public function getPrice(): float
{
return $this->price;
}
public function getCurrency(): string
{
return $this->currency;
}
public function getRule(): string
{
return $this->rule;
}
}

View file

@ -30,6 +30,7 @@ class TouristAttraction extends AbstractEntity
protected string $title = ''; protected string $title = '';
protected string $description = ''; protected string $description = '';
protected ?OpeningHours $openingHours = null; protected ?OpeningHours $openingHours = null;
protected ?Offers $offers = null;
protected ?Address $address = null; protected ?Address $address = null;
protected ?Town $town = null; protected ?Town $town = null;
protected ?Media $media = null; protected ?Media $media = null;
@ -49,6 +50,11 @@ class TouristAttraction extends AbstractEntity
return $this->openingHours; return $this->openingHours;
} }
public function getOffers(): ?Offers
{
return $this->offers;
}
public function getAddress(): ?Address public function getAddress(): ?Address
{ {
return $this->address; return $this->address;

View file

@ -14,8 +14,7 @@ defined('TYPO3') or die();
], ],
'types' => [ 'types' => [
$cType => [ $cType => [
'showitem' => 'showitem' => '--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,'
'--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,'
. '--palette--;;general,' . '--palette--;;general,'
. '--palette--;;headers,' . '--palette--;;headers,'
. 'records,' . 'records,'

View file

@ -101,6 +101,14 @@ return (static function (string $extensionKey, string $tableName) {
'readOnly' => true, 'readOnly' => true,
], ],
], ],
'offers' => [
'label' => $languagePath . '.offers',
'l10n_mode' => 'exclude',
'config' => [
'type' => 'text',
'readOnly' => true,
],
],
'remote_id' => [ 'remote_id' => [
'label' => $languagePath . '.remote_id', 'label' => $languagePath . '.remote_id',
'l10n_mode' => 'exclude', 'l10n_mode' => 'exclude',
@ -150,7 +158,7 @@ return (static function (string $extensionKey, string $tableName) {
], ],
'types' => [ 'types' => [
'0' => [ '0' => [
'showitem' => '--palette--;;language, title, description, opening_hours, address, media, remote_id, --div--;' . $languagePath . '.tab.relations, town, managed_by', 'showitem' => '--palette--;;language, title, description, opening_hours, offers, address, media, remote_id, --div--;' . $languagePath . '.tab.relations, town, managed_by',
], ],
], ],
]; ];

View file

@ -106,6 +106,16 @@
<trans-unit id="controller.backend.import.import.error.text" xml:space="preserve"> <trans-unit id="controller.backend.import.import.error.text" xml:space="preserve">
<source>Imported configuration "%1$s". But had at least one error.</source> <source>Imported configuration "%1$s". But had at least one error.</source>
</trans-unit> </trans-unit>
<trans-unit id="content.price.rule.PerPackage" xml:space="preserve">
<source>pro Paket</source>
</trans-unit>
<trans-unit id="content.price.rule.PerGroup" xml:space="preserve">
<source>pro Gruppe</source>
</trans-unit>
<trans-unit id="content.price.rule.PerPerson" xml:space="preserve">
<source>pro Person</source>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View file

@ -102,6 +102,9 @@
<trans-unit id="tx_thuecat_tourist_attraction.media" xml:space="preserve"> <trans-unit id="tx_thuecat_tourist_attraction.media" xml:space="preserve">
<source>Media</source> <source>Media</source>
</trans-unit> </trans-unit>
<trans-unit id="tx_thuecat_tourist_attraction.offers" xml:space="preserve">
<source>Offers</source>
</trans-unit>
<trans-unit id="tx_thuecat_tourist_attraction.town" xml:space="preserve"> <trans-unit id="tx_thuecat_tourist_attraction.town" xml:space="preserve">
<source>Town</source> <source>Town</source>
</trans-unit> </trans-unit>

View file

@ -27,5 +27,22 @@
{entity.address.fax} {entity.address.fax}
</p> </p>
</f:if> </f:if>
<f:if condition="{entity.offers}">
<f:for each="{entity.offers}" as="offer">
<h3>{offer.title}</h3>
<f:if condition="{offer.description}">
<p>{offer.description}</p>
</f:if>
<f:for each="{offer.prices}" as="price">
<h4>{price.title}</h4>
<f:if condition="{price.description}">
<p>{price.description}</p>
</f:if>
{price.price -> f:format.currency(decimalSeparator: ',', thousandsSeparator: '.', decimals: 2, currencySign: price.currency)}
{f:translate(id: 'content.price.rule.{price.rule}', default: price.rule, extensionName: 'Thuecat')}
</f:for>
</f:for>
</f:if>
</f:for> </f:for>
</html> </html>

View file

@ -1,10 +1,10 @@
tx_thuecat_tourist_attraction tx_thuecat_tourist_attraction
,"uid","pid","sys_language_uid","l18n_parent","l10n_source","l10n_state","remote_id","title","managed_by","town","address" ,"uid","pid","sys_language_uid","l18n_parent","l10n_source","l10n_state","remote_id","title","managed_by","town","address","offers"
,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}}" ,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}}","[]"
,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}}" ,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}}","[]"
,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}}" ,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""}]}]"
,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}}" ,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""}]}]"
,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}}" ,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""}]}]"
,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}}" ,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}}","[]"
,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}}" ,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}}","[]"
,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}}" ,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}}","[]"

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

View file

@ -55,7 +55,10 @@ use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase as TestCase;
* @uses WerkraumMedia\ThueCat\Domain\Import\Importer\LanguageHandling * @uses WerkraumMedia\ThueCat\Domain\Import\Importer\LanguageHandling
* @uses WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser * @uses WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser
* @uses WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Address * @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\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\JsonLD\Parser\OpeningHours * @uses WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\OpeningHours
* @uses WerkraumMedia\ThueCat\Domain\Import\Model\EntityCollection * @uses WerkraumMedia\ThueCat\Domain\Import\Model\EntityCollection

View file

@ -28,6 +28,7 @@ use Prophecy\PhpUnit\ProphecyTrait;
use WerkraumMedia\ThueCat\Domain\Import\Converter\TouristAttraction; use WerkraumMedia\ThueCat\Domain\Import\Converter\TouristAttraction;
use WerkraumMedia\ThueCat\Domain\Import\Importer\LanguageHandling; use WerkraumMedia\ThueCat\Domain\Import\Importer\LanguageHandling;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser; 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\EntityCollection;
use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration; use WerkraumMedia\ThueCat\Domain\Model\Backend\ImportConfiguration;
use WerkraumMedia\ThueCat\Domain\Model\Backend\Organisation; use WerkraumMedia\ThueCat\Domain\Model\Backend\Organisation;
@ -50,12 +51,14 @@ class TouristAttractionTest extends TestCase
public function canBeCreated(): void public function canBeCreated(): void
{ {
$parser = $this->prophesize(Parser::class); $parser = $this->prophesize(Parser::class);
$parserForOffers = $this->prophesize(Offers::class);
$language = $this->prophesize(LanguageHandling::class); $language = $this->prophesize(LanguageHandling::class);
$organisationRepository = $this->prophesize(OrganisationRepository::class); $organisationRepository = $this->prophesize(OrganisationRepository::class);
$townRepository = $this->prophesize(TownRepository::class); $townRepository = $this->prophesize(TownRepository::class);
$subject = new TouristAttraction( $subject = new TouristAttraction(
$parser->reveal(), $parser->reveal(),
$parserForOffers->reveal(),
$language->reveal(), $language->reveal(),
$organisationRepository->reveal(), $organisationRepository->reveal(),
$townRepository->reveal() $townRepository->reveal()
@ -70,12 +73,14 @@ class TouristAttractionTest extends TestCase
public function canConvert(): void public function canConvert(): void
{ {
$parser = $this->prophesize(Parser::class); $parser = $this->prophesize(Parser::class);
$parserForOffers = $this->prophesize(Offers::class);
$language = $this->prophesize(LanguageHandling::class); $language = $this->prophesize(LanguageHandling::class);
$organisationRepository = $this->prophesize(OrganisationRepository::class); $organisationRepository = $this->prophesize(OrganisationRepository::class);
$townRepository = $this->prophesize(TownRepository::class); $townRepository = $this->prophesize(TownRepository::class);
$subject = new TouristAttraction( $subject = new TouristAttraction(
$parser->reveal(), $parser->reveal(),
$parserForOffers->reveal(),
$language->reveal(), $language->reveal(),
$organisationRepository->reveal(), $organisationRepository->reveal(),
$townRepository->reveal() $townRepository->reveal()
@ -126,6 +131,9 @@ class TouristAttractionTest extends TestCase
$parser->getAddress($jsonLD)->willReturn([]); $parser->getAddress($jsonLD)->willReturn([]);
$parser->getMedia($jsonLD)->willReturn([]); $parser->getMedia($jsonLD)->willReturn([]);
$parserForOffers = $this->prophesize(Offers::class);
$parserForOffers->get($jsonLD, 'de')->willReturn([]);
$language = $this->prophesize(LanguageHandling::class); $language = $this->prophesize(LanguageHandling::class);
$language->isUnknown('de', 10)->willReturn(false); $language->isUnknown('de', 10)->willReturn(false);
$language->getSystemUid('de', 10)->willReturn(0); $language->getSystemUid('de', 10)->willReturn(0);
@ -138,6 +146,7 @@ class TouristAttractionTest extends TestCase
$subject = new TouristAttraction( $subject = new TouristAttraction(
$parser->reveal(), $parser->reveal(),
$parserForOffers->reveal(),
$language->reveal(), $language->reveal(),
$organisationRepository->reveal(), $organisationRepository->reveal(),
$townRepository->reveal() $townRepository->reveal()
@ -160,6 +169,7 @@ class TouristAttractionTest extends TestCase
'opening_hours' => '[]', 'opening_hours' => '[]',
'address' => '[]', 'address' => '[]',
'media' => '[]', 'media' => '[]',
'offers' => '[]',
], $entity->getData()); ], $entity->getData());
} }
@ -205,6 +215,9 @@ class TouristAttractionTest extends TestCase
$parser->getAddress($jsonLD)->willReturn([]); $parser->getAddress($jsonLD)->willReturn([]);
$parser->getMedia($jsonLD)->willReturn([]); $parser->getMedia($jsonLD)->willReturn([]);
$parserForOffers = $this->prophesize(Offers::class);
$parserForOffers->get($jsonLD, 'de')->willReturn([]);
$language = $this->prophesize(LanguageHandling::class); $language = $this->prophesize(LanguageHandling::class);
$language->isUnknown('de', 10)->willReturn(false); $language->isUnknown('de', 10)->willReturn(false);
$language->getSystemUid('de', 10)->willReturn(0); $language->getSystemUid('de', 10)->willReturn(0);
@ -227,6 +240,7 @@ class TouristAttractionTest extends TestCase
$subject = new TouristAttraction( $subject = new TouristAttraction(
$parser->reveal(), $parser->reveal(),
$parserForOffers->reveal(),
$language->reveal(), $language->reveal(),
$organisationRepository->reveal(), $organisationRepository->reveal(),
$townRepository->reveal() $townRepository->reveal()
@ -249,6 +263,7 @@ class TouristAttractionTest extends TestCase
'opening_hours' => '[]', 'opening_hours' => '[]',
'address' => '[]', 'address' => '[]',
'media' => '[]', 'media' => '[]',
'offers' => '[]',
], $entity->getData()); ], $entity->getData());
} }
} }

View file

@ -0,0 +1,95 @@
<?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\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
{
$languageValues = $this->prophesize(LanguageValues::class);
$languageValues->getValueForLanguage([
'@value' => 'DE Title',
], 'de')->willReturn('DE Title');
$subject = new GenericFields(
$languageValues->reveal()
);
$result = $subject->getTitle([
'schema:name' => [
'@value' => 'DE Title',
],
], 'de');
self::assertSame('DE Title', $result);
}
/**
* @test
*/
public function returnsDescription(): void
{
$languageValues = $this->prophesize(LanguageValues::class);
$languageValues->getValueForLanguage([
'@value' => 'DE Description',
], 'de')->willReturn('DE Description');
$subject = new GenericFields(
$languageValues->reveal()
);
$result = $subject->getDescription([
'schema:description' => [
'@value' => 'DE Description',
],
], 'de');
self::assertSame('DE Description', $result);
}
}

View file

@ -0,0 +1,147 @@
<?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\LanguageValues;
/**
* @covers WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\LanguageValues
*/
class LanguageValuesTest extends TestCase
{
/**
* @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
{
$subject = new LanguageValues(
);
$result = $subject->getValueForLanguage($jsonLD, $language);
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 lanugages, no language specified' => [
'jsonLD' => [
[
'@language' => 'de',
'@value' => 'DE value',
],
[
'@language' => 'fr',
'@value' => 'FR value',
],
],
'language' => '',
'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, no language specified' => [
'jsonLD' => [
'@language' => 'de',
'@value' => 'DE value',
],
'language' => '',
'expected' => 'DE value',
],
'has single language, missing @language key' => [
'jsonLD' => [
'@value' => 'DE value',
],
'language' => '',
'expected' => '',
],
];
}
}

View file

@ -0,0 +1,349 @@
<?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\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
{
$genericFields = $this->prophesize(GenericFields::class);
$subject = new Offers(
$genericFields->reveal()
);
$result = $subject->get([], '');
self::assertSame([], $result);
}
/**
* @test
*/
public function returnsSingleOfferWithSinglePrice(): void
{
$jsonLD = [
'schema:makesOffer' => [
[
'@id' => 'genid-28b33237f71b41e3ad54a99e1da769b9-b5',
'@type' => [
0 => 'schema:Intangible',
1 => 'schema:Thing',
2 => 'schema:Offer',
],
'rdfs:label' => [
'@language' => 'de',
'@value' => 'Führungen',
],
'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',
],
'rdfs:label' => [
'@language' => 'de',
'@value' => 'Erwachsene',
],
'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',
],
'rdfs:label' => [
'@language' => 'de',
'@value' => 'Ermäßigt',
],
'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',
],
'rdfs:label' => [
'@language' => 'de',
'@value' => 'Eintritt',
],
'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',
],
'rdfs:label' => [
'@language' => 'de',
'@value' => 'Ermäßigt',
],
'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',
],
'rdfs:label' => [
'@language' => 'de',
'@value' => 'Familienkarte',
],
'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',
],
],
],
];
$genericFields = $this->prophesize(GenericFields::class);
// Offer 1
$genericFields->getTitle($jsonLD['schema:makesOffer'][0], 'de')->willReturn('Führungen');
$genericFields->getDescription($jsonLD['schema:makesOffer'][0], 'de')->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],
'de'
)->willReturn('Erwachsene');
$genericFields->getDescription(
$jsonLD['schema:makesOffer'][0]['schema:priceSpecification'][0],
'de'
)->willReturn('');
$genericFields->getTitle(
$jsonLD['schema:makesOffer'][0]['schema:priceSpecification'][1],
'de'
)->willReturn('Ermäßigt');
$genericFields->getDescription(
$jsonLD['schema:makesOffer'][0]['schema:priceSpecification'][1],
'de'
)->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], 'de')->willReturn('Eintritt');
$genericFields->getDescription($jsonLD['schema:makesOffer'][1], 'de')->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],
'de'
)->willReturn('Ermäßigt');
$genericFields->getDescription(
$jsonLD['schema:makesOffer'][1]['schema:priceSpecification'][0],
'de'
)->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],
'de'
)->willReturn('Familienkarte');
$genericFields->getDescription(
$jsonLD['schema:makesOffer'][1]['schema:priceSpecification'][1],
'de'
)->willReturn('');
$subject = new Offers(
$genericFields->reveal()
);
$result = $subject->get($jsonLD, 'de');
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);
}
}

View file

@ -27,6 +27,7 @@ use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait; use Prophecy\PhpUnit\ProphecyTrait;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser; use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\Address; 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\Media;
use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\OpeningHours; use WerkraumMedia\ThueCat\Domain\Import\JsonLD\Parser\OpeningHours;
@ -42,10 +43,13 @@ class ParserTest extends TestCase
*/ */
public function canBeCreated(): void public function canBeCreated(): void
{ {
$genericFields = $this->prophesize(GenericFields::class);
$openingHours = $this->prophesize(OpeningHours::class); $openingHours = $this->prophesize(OpeningHours::class);
$address = $this->prophesize(Address::class); $address = $this->prophesize(Address::class);
$media = $this->prophesize(Media::class); $media = $this->prophesize(Media::class);
$subject = new Parser( $subject = new Parser(
$genericFields->reveal(),
$openingHours->reveal(), $openingHours->reveal(),
$address->reveal(), $address->reveal(),
$media->reveal() $media->reveal()
@ -59,10 +63,13 @@ class ParserTest extends TestCase
*/ */
public function returnsId(): void public function returnsId(): void
{ {
$genericFields = $this->prophesize(GenericFields::class);
$openingHours = $this->prophesize(OpeningHours::class); $openingHours = $this->prophesize(OpeningHours::class);
$address = $this->prophesize(Address::class); $address = $this->prophesize(Address::class);
$media = $this->prophesize(Media::class); $media = $this->prophesize(Media::class);
$subject = new Parser( $subject = new Parser(
$genericFields->reveal(),
$openingHours->reveal(), $openingHours->reveal(),
$address->reveal(), $address->reveal(),
$media->reveal() $media->reveal()
@ -78,12 +85,77 @@ class ParserTest extends TestCase
/** /**
* @test * @test
*/ */
public function returnsManagerId(): void public function returnsTitle(): void
{ {
$jsonLD = [
'schema:name' => [
'@language' => 'de',
'@value' => 'Erfurt',
],
];
$genericFields = $this->prophesize(GenericFields::class);
$genericFields->getTitle($jsonLD, 'de')->willReturn('Erfurt');
$openingHours = $this->prophesize(OpeningHours::class); $openingHours = $this->prophesize(OpeningHours::class);
$address = $this->prophesize(Address::class); $address = $this->prophesize(Address::class);
$media = $this->prophesize(Media::class); $media = $this->prophesize(Media::class);
$subject = new Parser( $subject = new Parser(
$genericFields->reveal(),
$openingHours->reveal(),
$address->reveal(),
$media->reveal()
);
$result = $subject->getTitle($jsonLD, 'de');
self::assertSame('Erfurt', $result);
}
/**
* @test
*/
public function returnsDescription(): void
{
$jsonLD = [
'schema:description' => [
'@language' => 'de',
'@value' => 'Erfurt',
],
];
$genericFields = $this->prophesize(GenericFields::class);
$genericFields->getDescription($jsonLD, 'de')->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, 'de');
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(), $openingHours->reveal(),
$address->reveal(), $address->reveal(),
$media->reveal() $media->reveal()
@ -98,269 +170,18 @@ class ParserTest extends TestCase
self::assertSame('https://example.com/resources/165868194223-manager', $result); self::assertSame('https://example.com/resources/165868194223-manager', $result);
} }
/**
* @test
* @dataProvider titles
*/
public function returnsTitle(array $jsonLD, string $language, string $expected): void
{
$openingHours = $this->prophesize(OpeningHours::class);
$address = $this->prophesize(Address::class);
$media = $this->prophesize(Media::class);
$subject = new Parser(
$openingHours->reveal(),
$address->reveal(),
$media->reveal()
);
$result = $subject->getTitle($jsonLD, $language);
self::assertSame($expected, $result);
}
public function titles(): array
{
return [
'json has multiple lanugages, one matches' => [
'jsonLD' => [
'schema:name' => [
[
'@language' => 'de',
'@value' => 'DE Title',
],
[
'@language' => 'fr',
'@value' => 'FR Title',
],
],
],
'language' => 'de',
'expected' => 'DE Title',
],
'json has multiple lanugages, no language specified' => [
'jsonLD' => [
'schema:name' => [
[
'@language' => 'de',
'@value' => 'DE Title',
],
[
'@language' => 'fr',
'@value' => 'FR Title',
],
],
],
'language' => '',
'expected' => 'DE Title',
],
'json has multiple languages, none matches' => [
'jsonLD' => [
'schema:name' => [
[
'@language' => 'de',
'@value' => 'DE Title',
],
[
'@language' => 'fr',
'@value' => 'FR Title',
],
],
],
'language' => 'en',
'expected' => '',
],
'json has multiple languages, missing @language key' => [
'jsonLD' => [
'schema:name' => [
[
'@value' => 'DE Title',
],
[
'@value' => 'FR Title',
],
],
],
'language' => 'en',
'expected' => '',
],
'json has single language, that one matches' => [
'jsonLD' => [
'schema:name' => [
'@language' => 'de',
'@value' => 'DE Title',
],
],
'language' => 'de',
'expected' => 'DE Title',
],
'json contains single language, but another is requested' => [
'jsonLD' => [
'schema:name' => [
'@language' => 'de',
'@value' => 'DE Title',
],
],
'language' => 'en',
'expected' => '',
],
'json contains single language, no language specified' => [
'jsonLD' => [
'schema:name' => [
'@language' => 'de',
'@value' => 'DE Title',
],
],
'language' => '',
'expected' => 'DE Title',
],
'json contains single language, missing @language key' => [
'jsonLD' => [
'schema:name' => [
'@value' => 'DE Title',
],
],
'language' => '',
'expected' => '',
],
];
}
/**
* @test
* @dataProvider descriptions
*/
public function returnsDescription(array $jsonLD, string $language, string $expected): void
{
$openingHours = $this->prophesize(OpeningHours::class);
$address = $this->prophesize(Address::class);
$media = $this->prophesize(Media::class);
$subject = new Parser(
$openingHours->reveal(),
$address->reveal(),
$media->reveal()
);
$result = $subject->getDescription($jsonLD, $language);
self::assertSame($expected, $result);
}
public function descriptions(): array
{
return [
'json has multiple lanugages, one matches' => [
'jsonLD' => [
'schema:description' => [
[
'@language' => 'de',
'@value' => 'DE Description',
],
[
'@language' => 'fr',
'@value' => 'FR Description',
],
],
],
'language' => 'de',
'expected' => 'DE Description',
],
'json has multiple lanugages, no language specified' => [
'jsonLD' => [
'schema:description' => [
[
'@language' => 'de',
'@value' => 'DE Description',
],
[
'@language' => 'fr',
'@value' => 'FR Description',
],
],
],
'language' => '',
'expected' => 'DE Description',
],
'json has multiple languages, none matches' => [
'jsonLD' => [
'schema:description' => [
[
'@language' => 'de',
'@value' => 'DE Description',
],
[
'@language' => 'fr',
'@value' => 'FR Description',
],
],
],
'language' => 'en',
'expected' => '',
],
'json has multiple languages, missing @language key' => [
'jsonLD' => [
'schema:description' => [
[
'@value' => 'DE Description',
],
[
'@value' => 'FR Description',
],
],
],
'language' => 'en',
'expected' => '',
],
'json has single language, that one matches' => [
'jsonLD' => [
'schema:description' => [
'@language' => 'de',
'@value' => 'DE Description',
],
],
'language' => 'de',
'expected' => 'DE Description',
],
'json contains single language, but another is requested' => [
'jsonLD' => [
'schema:description' => [
'@language' => 'de',
'@value' => 'DE Description',
],
],
'language' => 'en',
'expected' => '',
],
'json contains single language, no language specified' => [
'jsonLD' => [
'schema:description' => [
'@language' => 'de',
'@value' => 'DE Description',
],
],
'language' => '',
'expected' => 'DE Description',
],
'json contains single language, missing @language key' => [
'jsonLD' => [
'schema:description' => [
'@value' => 'DE Description',
],
],
'language' => '',
'expected' => '',
],
];
}
/** /**
* @test * @test
*/ */
public function returnsContainedInPlaceIds(): void public function returnsContainedInPlaceIds(): void
{ {
$genericFields = $this->prophesize(GenericFields::class);
$openingHours = $this->prophesize(OpeningHours::class); $openingHours = $this->prophesize(OpeningHours::class);
$address = $this->prophesize(Address::class); $address = $this->prophesize(Address::class);
$media = $this->prophesize(Media::class); $media = $this->prophesize(Media::class);
$subject = new Parser( $subject = new Parser(
$genericFields->reveal(),
$openingHours->reveal(), $openingHours->reveal(),
$address->reveal(), $address->reveal(),
$media->reveal() $media->reveal()
@ -390,10 +211,13 @@ class ParserTest extends TestCase
*/ */
public function returnsLanguages(): void public function returnsLanguages(): void
{ {
$genericFields = $this->prophesize(GenericFields::class);
$openingHours = $this->prophesize(OpeningHours::class); $openingHours = $this->prophesize(OpeningHours::class);
$address = $this->prophesize(Address::class); $address = $this->prophesize(Address::class);
$media = $this->prophesize(Media::class); $media = $this->prophesize(Media::class);
$subject = new Parser( $subject = new Parser(
$genericFields->reveal(),
$openingHours->reveal(), $openingHours->reveal(),
$address->reveal(), $address->reveal(),
$media->reveal() $media->reveal()
@ -428,10 +252,13 @@ class ParserTest extends TestCase
*/ */
public function throwsExceptionOnUnkownLanguage(): void public function throwsExceptionOnUnkownLanguage(): void
{ {
$genericFields = $this->prophesize(GenericFields::class);
$openingHours = $this->prophesize(OpeningHours::class); $openingHours = $this->prophesize(OpeningHours::class);
$address = $this->prophesize(Address::class); $address = $this->prophesize(Address::class);
$media = $this->prophesize(Media::class); $media = $this->prophesize(Media::class);
$subject = new Parser( $subject = new Parser(
$genericFields->reveal(),
$openingHours->reveal(), $openingHours->reveal(),
$address->reveal(), $address->reveal(),
$media->reveal() $media->reveal()
@ -453,10 +280,13 @@ class ParserTest extends TestCase
*/ */
public function returnsNoLanguagesIfInfoIsMissing(): void public function returnsNoLanguagesIfInfoIsMissing(): void
{ {
$genericFields = $this->prophesize(GenericFields::class);
$openingHours = $this->prophesize(OpeningHours::class); $openingHours = $this->prophesize(OpeningHours::class);
$address = $this->prophesize(Address::class); $address = $this->prophesize(Address::class);
$media = $this->prophesize(Media::class); $media = $this->prophesize(Media::class);
$subject = new Parser( $subject = new Parser(
$genericFields->reveal(),
$openingHours->reveal(), $openingHours->reveal(),
$address->reveal(), $address->reveal(),
$media->reveal() $media->reveal()
@ -489,11 +319,14 @@ class ParserTest extends TestCase
'daysOfWeek' => [], 'daysOfWeek' => [],
]; ];
$genericFields = $this->prophesize(GenericFields::class);
$openingHours = $this->prophesize(OpeningHours::class); $openingHours = $this->prophesize(OpeningHours::class);
$openingHours->get($jsonLD)->willReturn($generatedOpeningHours); $openingHours->get($jsonLD)->willReturn($generatedOpeningHours);
$address = $this->prophesize(Address::class); $address = $this->prophesize(Address::class);
$media = $this->prophesize(Media::class); $media = $this->prophesize(Media::class);
$subject = new Parser( $subject = new Parser(
$genericFields->reveal(),
$openingHours->reveal(), $openingHours->reveal(),
$address->reveal(), $address->reveal(),
$media->reveal() $media->reveal()
@ -527,12 +360,14 @@ class ParserTest extends TestCase
'fax' => '', 'fax' => '',
]; ];
$genericFields = $this->prophesize(GenericFields::class);
$openingHours = $this->prophesize(OpeningHours::class); $openingHours = $this->prophesize(OpeningHours::class);
$address = $this->prophesize(Address::class); $address = $this->prophesize(Address::class);
$address->get($jsonLD)->willReturn($generatedAddress); $address->get($jsonLD)->willReturn($generatedAddress);
$media = $this->prophesize(Media::class); $media = $this->prophesize(Media::class);
$subject = new Parser( $subject = new Parser(
$genericFields->reveal(),
$openingHours->reveal(), $openingHours->reveal(),
$address->reveal(), $address->reveal(),
$media->reveal() $media->reveal()
@ -583,12 +418,14 @@ class ParserTest extends TestCase
], ],
]; ];
$genericFields = $this->prophesize(GenericFields::class);
$openingHours = $this->prophesize(OpeningHours::class); $openingHours = $this->prophesize(OpeningHours::class);
$address = $this->prophesize(Address::class); $address = $this->prophesize(Address::class);
$media = $this->prophesize(Media::class); $media = $this->prophesize(Media::class);
$media->get($jsonLD)->willReturn($generatedMedia); $media->get($jsonLD)->willReturn($generatedMedia);
$subject = new Parser( $subject = new Parser(
$genericFields->reveal(),
$openingHours->reveal(), $openingHours->reveal(),
$address->reveal(), $address->reveal(),
$media->reveal() $media->reveal()

View file

@ -3,6 +3,7 @@
declare(strict_types=1); declare(strict_types=1);
use PhpCsFixer\Fixer\ArrayNotation\ArraySyntaxFixer; use PhpCsFixer\Fixer\ArrayNotation\ArraySyntaxFixer;
use PhpCsFixer\Fixer\ArrayNotation\NoMultilineWhitespaceAroundDoubleArrowFixer;
use PhpCsFixer\Fixer\ArrayNotation\TrailingCommaInMultilineArrayFixer; use PhpCsFixer\Fixer\ArrayNotation\TrailingCommaInMultilineArrayFixer;
use PhpCsFixer\Fixer\Import\FullyQualifiedStrictTypesFixer; use PhpCsFixer\Fixer\Import\FullyQualifiedStrictTypesFixer;
use PhpCsFixer\Fixer\Import\NoUnusedImportsFixer; use PhpCsFixer\Fixer\Import\NoUnusedImportsFixer;
@ -39,6 +40,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services->set(NoUnusedImportsFixer::class); $services->set(NoUnusedImportsFixer::class);
$services->set(FullyQualifiedStrictTypesFixer::class); $services->set(FullyQualifiedStrictTypesFixer::class);
$services->set(NoMultilineWhitespaceAroundDoubleArrowFixer::class);
$services->set(ArraySyntaxFixer::class)->call('configure', [[ $services->set(ArraySyntaxFixer::class)->call('configure', [[
'syntax' => 'short', 'syntax' => 'short',
]]); ]]);

View file

@ -55,4 +55,5 @@ CREATE TABLE tx_thuecat_tourist_attraction (
opening_hours text DEFAULT '' NOT NULL, opening_hours text DEFAULT '' NOT NULL,
address text DEFAULT '' NOT NULL, address text DEFAULT '' NOT NULL,
media text DEFAULT '' NOT NULL, media text DEFAULT '' NOT NULL,
offers text DEFAULT '' NOT NULL,
); );