diff --git a/config/services.yml b/config/services.yml index 4729013..b82f09a 100644 --- a/config/services.yml +++ b/config/services.yml @@ -32,6 +32,7 @@ services: Mummert\KsNossenerlandBundle\Service\SoapClientService: arguments: + $httpClient: '@GuzzleHttp\Client' $wsdlUrl: '%env(default:ks_nossenerland.soap_wsdl_url_fallback:KS_NOSSENERLAND_SOAP_WSDL_URL)%' $endpointUrl: '%env(default:ks_nossenerland.soap_endpoint_url_fallback:KS_NOSSENERLAND_SOAP_ENDPOINT_URL)%' $apiKey: '%env(default:ks_nossenerland.soap_api_key_fallback:KS_NOSSENERLAND_SOAP_API_KEY)%' diff --git a/contao/dca/tl_calendar_events.php b/contao/dca/tl_calendar_events.php index 015cf89..fe5be78 100644 --- a/contao/dca/tl_calendar_events.php +++ b/contao/dca/tl_calendar_events.php @@ -19,7 +19,7 @@ $fields = [ 'alt', 'imageTitle', 'size', 'imageUrl', 'caption', 'floating', 'repeatEach', 'repeatEnd', 'recurrences', 'enclosure', 'source', 'linkText', 'jumpTo', 'articleId', 'url', 'cssClass', 'start', 'stop', 'languageMain', 'catalog_ort', 'catalog_kontakt', 'godi_options', 'catalog_pfarrbereiche', 'styleManager', 'export', - 'external_location', 'evlkscalendar' + 'external_location', 'evlkscalendar', 'evlks_access' ]; foreach ($fields as $field) { @@ -143,6 +143,31 @@ $dca['fields']['export'] = [ 'sql' => "char(1) NOT NULL default ''", ]; +$dca['fields']['evlks_access'] = [ + 'label' => &$GLOBALS['TL_LANG']['tl_calendar_events']['evlks_access'], + 'exclude' => false, + 'inputType' => 'select', + 'options' => [ + 1 => 'Veranstaltung in Gebaerdensprache bzw. Gebaerdendolmetscher ist anwesend', + 2 => 'Predigt / Liturgie der Veranstaltung liegt in schriftlicher Form vor', + 3 => 'Veranstaltung findet in Leichter Sprache statt', + 4 => 'Gebaerdensprachdolmetscher kann bei Bedarf bestellt werden', + 5 => 'Abholung oder Fahrdienst kann bei Bedarf organisiert werden', + 6 => 'Induktive Hoeranlage', + 7 => 'FM-Anlage (drahtlose Funkanlage)', + 8 => 'Punktschrift / Grossdruck auf Anfrage', + 9 => 'Begleitservice auf Anfrage', + ], + 'eval' => [ + 'multiple' => true, + 'chosen' => true, + 'csv' => ',', + 'includeBlankOption' => true, + 'tl_class' => 'w50 clr', + ], + 'sql' => "text NULL", +]; + $dca['fields']['external_location'] = [ 'label' => &$GLOBALS['TL_LANG']['tl_calendar_events']['external_location'], 'inputType' => 'select', @@ -182,6 +207,7 @@ PaletteManipulator::create() ->addField('subtitle', 'title_legend', PaletteManipulator::POSITION_APPEND) ->addField('evlkscalendar', 'nossenerland_legend', PaletteManipulator::POSITION_APPEND) ->addField('export', 'nossenerland_legend', PaletteManipulator::POSITION_APPEND) + ->addField('evlks_access', 'nossenerland_legend', PaletteManipulator::POSITION_APPEND) ->addField('contributors', 'address') ->addField('catalog_kontakt', 'address') ->addField('catalog_pfarrbereiche', 'address') diff --git a/contao/languages/de/tl_calendar_events.php b/contao/languages/de/tl_calendar_events.php index b0a61b2..a651113 100644 --- a/contao/languages/de/tl_calendar_events.php +++ b/contao/languages/de/tl_calendar_events.php @@ -23,6 +23,9 @@ $lang['export'][1] = 'auswählen wenn die Veranstaltung auc $lang['evlkscalendar'][0] = 'Veranstaltung nicht auf EVLKS Kaelnder zeigen'; $lang['evlkscalendar'][1] = 'wenn ausgewählt, wird die Veranstaltung nicht zum EVLKS Kalender exportiert'; +$lang['evlks_access'][0] = 'Angaben zur Barrierefreiheit (EVLKS)'; +$lang['evlks_access'][1] = 'Auswahl wird als Feld "access" an die EVLKS SOAP API uebertragen.'; + $lang['external_location'][0] = 'Veranstaltungsort aus nossener-land.de Datenbank'; $lang['external_location'][1] = 'Export funktioniert nur mit Veranstaltungsort aus nossener-land.de Datenbank'; diff --git a/src/Command/ExportEventsCommand.php b/src/Command/ExportEventsCommand.php index 3434717..6de5f53 100644 --- a/src/Command/ExportEventsCommand.php +++ b/src/Command/ExportEventsCommand.php @@ -12,6 +12,7 @@ class ExportEventsCommand extends Command { private $connection; private $soapClientService; + private const BATCH_SIZE = 200; public function __construct(Connection $connection, SoapClientService $soapClientService) { @@ -29,21 +30,35 @@ class ExportEventsCommand extends Command { $today = (new \DateTimeImmutable('today'))->getTimestamp(); - $stmt = $this->connection->executeQuery( - 'SELECT * FROM tl_calendar_events WHERE pid IN (1, 2, 3) AND evlkscalendar != 1 AND ( - (endDate IS NOT NULL AND endDate >= ?) OR (endDate IS NULL AND startDate >= ?) - )', - [$today, $today] - ); - $exportedIds = []; $exportCount = 0; - while ($event = $stmt->fetchAssociative()) { - $response = $this->soapClientService->sendEventToSoapAPI($event); - if ($response) { - $exportedIds[] = (string) $event['id']; - $exportCount++; + $lastId = 0; + + while (true) { + $rows = $this->connection->executeQuery( + 'SELECT * FROM tl_calendar_events + WHERE pid IN (1, 2, 3) + AND evlkscalendar != 1 + AND ((endDate IS NOT NULL AND endDate >= ?) OR (endDate IS NULL AND startDate >= ?)) + AND id > ? + ORDER BY id ASC + LIMIT ' . self::BATCH_SIZE, + [$today, $today, $lastId] + )->fetchAllAssociative(); + + if (empty($rows)) { + break; + } + + foreach ($rows as $event) { + $response = $this->soapClientService->sendEventToSoapAPI($event); + if ($response) { + $exportedIds[] = (string) $event['id']; + $exportCount++; + } + + $lastId = (int) $event['id']; } } diff --git a/src/Service/SoapClientService.php b/src/Service/SoapClientService.php index d7fce07..d84d457 100644 --- a/src/Service/SoapClientService.php +++ b/src/Service/SoapClientService.php @@ -7,6 +7,7 @@ use SoapHeader; use Exception; use StdClass; use Doctrine\DBAL\Connection; +use GuzzleHttp\Client; class SoapClientService { @@ -14,10 +15,12 @@ class SoapClientService private string $apiKey; private string $vid; private Connection $connection; + private Client $httpClient; - public function __construct(Connection $connection, string $wsdlUrl, string $endpointUrl, string $apiKey, string $vid) + public function __construct(Connection $connection, Client $httpClient, string $wsdlUrl, string $endpointUrl, string $apiKey, string $vid) { $this->connection = $connection; + $this->httpClient = $httpClient; $this->apiKey = $apiKey; $this->vid = $vid; @@ -211,6 +214,7 @@ class SoapClientService $link = 'https://kirchspiel-nossener-land.de/termine/' . $eventData['alias']; $menue1 = (isset($eventData['godi_options']) && in_array('2', explode(',', $eventData['godi_options']))) ? 100 : null; + $access = $this->normalizeCsvSelection($eventData['evlks_access'] ?? null, range(1, 9)); $event = [ 'externalid' => strval($eventData['id']), @@ -233,6 +237,7 @@ class SoapClientService 'textline1' => $people, 'people' => null, 'menue1' => $menue1, + 'access' => $access, 'kollekte' => 0, ]; @@ -244,6 +249,19 @@ class SoapClientService } } + private function normalizeCsvSelection(?string $csv, array $allowedIds): ?string + { + if (null === $csv || '' === trim($csv)) { + return null; + } + + $allowed = array_map('strval', $allowedIds); + $items = array_filter(array_map('trim', explode(',', $csv)), static fn ($v) => '' !== $v); + $items = array_values(array_unique(array_filter($items, static fn ($v) => in_array($v, $allowed, true)))); + + return empty($items) ? null : implode(',', $items); + } + public function deleteEventByExternalId(string $externalId): bool { if (!$this->client instanceof SoapClient) { @@ -272,9 +290,25 @@ class SoapClientService { $url = 'https://kalender.evlks.de/json?vid=' . $this->vid; - $json = @file_get_contents($url); - if (!$json) { - error_log("❌ Fehler beim Abrufen der JSON-Daten von $url"); + try { + $response = $this->httpClient->request('GET', $url, [ + 'timeout' => 3.0, + 'connect_timeout' => 2.0, + 'http_errors' => false, + ]); + } catch (Exception $e) { + error_log("❌ Fehler beim Abrufen der JSON-Daten von $url: " . $e->getMessage()); + return []; + } + + if (200 !== $response->getStatusCode()) { + error_log("❌ EVLKS JSON antwortete mit HTTP " . $response->getStatusCode()); + return []; + } + + $json = (string) $response->getBody(); + if ('' === $json) { + error_log("❌ Leere JSON-Antwort von $url"); return []; }