Skip to content

Commit

Permalink
Handle broken opening hours
Browse files Browse the repository at this point in the history
Those are skipped during import and written as error to TYPO3 logs.
That way entries with broken opening hours can still be imported.

Resolves: #11377
  • Loading branch information
d-s-codappix committed Sep 9, 2024
1 parent 8c4e33a commit a873862
Show file tree
Hide file tree
Showing 8 changed files with 262 additions and 13 deletions.
30 changes: 30 additions & 0 deletions Classes/Domain/Import/Entity/InvalidDataException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

/*
* Copyright (C) 2024 Daniel Siepmann <[email protected]>
*
* 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 Exception;

final class InvalidDataException extends Exception
{
}
18 changes: 14 additions & 4 deletions Classes/Domain/Import/Entity/Properties/OpeningHour.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

namespace WerkraumMedia\ThueCat\Domain\Import\Entity\Properties;

use WerkraumMedia\ThueCat\Domain\Import\Entity\InvalidDataException;

class OpeningHour
{
/**
Expand All @@ -36,14 +38,14 @@ class OpeningHour
protected $validThrough = null;

/**
* @var \DateTimeImmutable
* @var \DateTimeImmutable|null
*/
protected $opens;
protected $opens = null;

/**
* @var \DateTimeImmutable
* @var \DateTimeImmutable|null
*/
protected $closes;
protected $closes = null;

/**
* @var string[]
Expand All @@ -62,11 +64,19 @@ public function getValidThrough(): ?\DateTimeImmutable

public function getOpens(): \DateTimeImmutable
{
if ($this->opens === null) {
throw new InvalidDataException('Opens was empty for opening hour.');
}

return $this->opens;
}

public function getCloses(): \DateTimeImmutable
{
if ($this->closes === null) {
throw new InvalidDataException('Closes was empty for opening hour.');
}

return $this->closes;
}

Expand Down
23 changes: 16 additions & 7 deletions Classes/Domain/Import/Typo3Converter/GeneralConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
use WerkraumMedia\ThueCat\Domain\Import\Entity\AccessibilitySpecification;
use WerkraumMedia\ThueCat\Domain\Import\Entity\Base;
use WerkraumMedia\ThueCat\Domain\Import\Entity\InvalidDataException;
use WerkraumMedia\ThueCat\Domain\Import\Entity\MapsToType;
use WerkraumMedia\ThueCat\Domain\Import\Entity\MediaObject;
use WerkraumMedia\ThueCat\Domain\Import\Entity\Minimum;
Expand Down Expand Up @@ -424,13 +425,21 @@ private function getOpeningHours(array $openingHours): string
$data = [];

foreach ($openingHours as $openingHour) {
$data[] = array_filter([
'opens' => $openingHour->getOpens()->format('H:i:s'),
'closes' => $openingHour->getCloses()->format('H:i:s'),
'from' => $openingHour->getValidFrom() ?? '',
'through' => $openingHour->getValidThrough() ?? '',
'daysOfWeek' => $openingHour->getDaysOfWeek(),
]);
try {
$data[] = array_filter([
'opens' => $openingHour->getOpens()->format('H:i:s'),
'closes' => $openingHour->getCloses()->format('H:i:s'),
'from' => $openingHour->getValidFrom() ?? '',
'through' => $openingHour->getValidThrough() ?? '',
'daysOfWeek' => $openingHour->getDaysOfWeek(),
]);
} catch (InvalidDataException $e) {
$this->logger->error('Could not import opening hour due to type error: ' . $e->getMessage(), [
'errorMessage' => $e->getMessage(),
'openingHour' => var_export($openingHour, true),
]);
continue;
}
}

return json_encode($data) ?: '';
Expand Down
4 changes: 3 additions & 1 deletion Documentation/Changelog/2.2.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ Features
Fixes
-----

Nothing
* Handle broken opening hours.
Those are skipped during import and written as error to TYPO3 logs.
That way entries with broken opening hours can still be imported.

Tasks
-----
Expand Down
7 changes: 6 additions & 1 deletion Tests/Functional/AbstractImportTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,12 @@ private function getLogFiles(): array
{
return [
self::getInstancePath() . '/typo3temp/var/log/typo3_0493d91d8e.log',
self::getInstancePath() . '/typo3temp/var/log/typo3_error_0493d91d8e.log',
$this->getErrorLogFile(),
];
}

protected function getErrorLogFile(): string
{
return self::getInstancePath() . '/typo3temp/var/log/typo3_error_0493d91d8e.log';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
{
"@context": {
"cdb": "https://thuecat.org/ontology/cdb/1.0/",
"dachkg": "https://thuecat.org/ontology/dachkg/1.0/",
"dbo": "http://dbpedia.org/ontology/",
"dsv": "http://ontologies.sti-innsbruck.at/dsv/",
"foaf": "http://xmlns.com/foaf/0.1/",
"owl": "http://www.w3.org/2002/07/owl#",
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
"schema": "http://schema.org/",
"sh": "http://www.w3.org/ns/shacl#",
"thuecat": "https://thuecat.org/ontology/thuecat/1.0/",
"ttgds": "https://thuecat.org/ontology/ttgds/1.0/",
"xsd": "http://www.w3.org/2001/XMLSchema#"
},
"@graph": [
{
"@id": "https://thuecat.org/resources/attraction-with-broken-opening-hour",
"@type": [
"schema:Place",
"schema:Thing",
"schema:TouristAttraction",
"ttgds:PointOfInterest"
],
"schema:name": {
"@language": "de",
"@value": "One specialOpeningHoursSpecification misses opens and closes, leading to type error"
},
"schema:availableLanguage": [
{
"@type": "thuecat:Language",
"@value": "thuecat:German"
},
{
"@type": "thuecat:Language",
"@value": "thuecat:English"
}
],
"schema:specialOpeningHoursSpecification": [
{
"@id": "genid-1dccaefc0e06401c93068c8081b7ea8c294892-b11",
"@type": [
"schema:Thing",
"schema:Intangible",
"schema:StructuredValue",
"schema:OpeningHoursSpecification"
],
"schema:dayOfWeek": {
"@type": "schema:DayOfWeek",
"@value": "schema:Thursday"
},
"schema:validThrough": {
"@type": "schema:Date",
"@value": "2024-09-19"
},
"schema:validFrom": {
"@type": "schema:Date",
"@value": "2024-09-19"
}
},
{
"@id": "genid-1dccaefc0e06401c93068c8081b7ea8c294892-b12",
"@type": [
"schema:Thing",
"schema:Intangible",
"schema:StructuredValue",
"schema:OpeningHoursSpecification"
],
"schema:opens": {
"@type": "schema:Time",
"@value": "09:30:00"
},
"schema:closes": {
"@type": "schema:Time",
"@value": "18:00:00"
},
"schema:dayOfWeek": {
"@type": "schema:DayOfWeek",
"@value": "schema:Thursday"
},
"schema:validThrough": {
"@type": "schema:Date",
"@value": "2024-09-19"
},
"schema:validFrom": {
"@type": "schema:Date",
"@value": "2024-09-19"
}
}
],
"thuecat:contentResponsible": {
"@id": "https://thuecat.org/resources/018132452787-ngbe"
}
}
]
}
68 changes: 68 additions & 0 deletions Tests/Functional/Fixtures/Import/ImportsWithBrokenOpeningHour.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<dataset>
<pages>
<uid>1</uid>
<pid>0</pid>
<tstamp>1613400587</tstamp>
<crdate>1613400558</crdate>
<cruser_id>1</cruser_id>
<doktype>4</doktype>
<title>Rootpage</title>
<is_siteroot>1</is_siteroot>
</pages>
<pages>
<uid>10</uid>
<pid>1</pid>
<tstamp>1613400587</tstamp>
<crdate>1613400558</crdate>
<cruser_id>1</cruser_id>
<doktype>254</doktype>
<title>Storage folder</title>
</pages>

<sys_language>
<uid>1</uid>
<pid>0</pid>
<title>English</title>
<flag>en-us-gb</flag>
<language_isocode>en</language_isocode>
</sys_language>

<tx_thuecat_import_configuration>
<uid>1</uid>
<pid>0</pid>
<tstamp>1613400587</tstamp>
<crdate>1613400558</crdate>
<cruser_id>1</cruser_id>
<disable>0</disable>
<title>Tourist Attraction</title>
<type>static</type>
<configuration><![CDATA[<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<T3FlexForms>
<data>
<sheet index="sDEF">
<language index="lDEF">
<field index="storagePid">
<value index="vDEF">10</value>
</field>
<field index="urls">
<el index="el">
<field index="602a89f54d694654233086">
<value index="url">
<el>
<field index="url">
<value index="vDEF">https://thuecat.org/resources/attraction-with-broken-opening-hour</value>
</field>
</el>
</value>
<value index="_TOGGLE">0</value>
</field>
</el>
</field>
</language>
</sheet>
</data>
</T3FlexForms>
]]></configuration>
</tx_thuecat_import_configuration>
</dataset>
28 changes: 28 additions & 0 deletions Tests/Functional/ImportTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,34 @@ public function importsTouristAttractionWithSingleSlogan(): void
$this->assertPHPDataSet(__DIR__ . '/Assertions/Import/ImportsTouristAttractionWithSingleSlogan.php');
}

/**
* @test
*/
public function importsWithBrokenOpeningHour(): void
{
$this->importDataSet(__DIR__ . '/Fixtures/Import/ImportsWithBrokenOpeningHour.xml');

GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/attraction-with-broken-opening-hour.json');
GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/018132452787-ngbe.json');

$this->importConfiguration();

$records = $this->getAllRecords('tx_thuecat_tourist_attraction');
self::assertCount(1, $this->getAllRecords('tx_thuecat_tourist_attraction'));
$specialOpeningHours = json_decode($records[0]['special_opening_hours'], true, 512, JSON_THROW_ON_ERROR);
self::assertIsArray($specialOpeningHours);
self::assertCount(1, $specialOpeningHours);

$this->expectErrors = true;
$loggedErrors = file_get_contents($this->getErrorLogFile());
self::assertIsString($loggedErrors);
self::assertStringContainsString(
'Could not import opening hour due to type error: Opens was empty for opening hour.',
$loggedErrors
);
self::assertStringContainsString('\'closes\' => NULL,', $loggedErrors);
}

private function importConfiguration(): void
{
$configuration = $this->get(ImportConfigurationRepository::class)->findByUid(1);
Expand Down

0 comments on commit a873862

Please sign in to comment.