Initial standalone bundle release (sanitized history)
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Mummert\KsNossenerlandBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Mummert\KsNossenerlandBundle\Service\SoapClientService;
|
||||
|
||||
class ExportEventsCommand extends Command
|
||||
{
|
||||
private $connection;
|
||||
private $soapClientService;
|
||||
|
||||
public function __construct(Connection $connection, SoapClientService $soapClientService)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->connection = $connection;
|
||||
$this->soapClientService = $soapClientService;
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setHelp('Dieses Kommando exportiert zukünftige Events nach EVLKS und löscht nicht mehr vorhandene.');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$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++;
|
||||
}
|
||||
}
|
||||
|
||||
$remoteExternalIds = $this->soapClientService->fetchRemoteExternalIds();
|
||||
$deletedCount = 0;
|
||||
|
||||
foreach ($remoteExternalIds as $externalId) {
|
||||
if (!in_array($externalId, $exportedIds, true)) {
|
||||
$response = $this->soapClientService->deleteEventByExternalId($externalId);
|
||||
if ($response) {
|
||||
$output->writeln("🗑️ gelöscht: $externalId");
|
||||
$deletedCount++;
|
||||
} else {
|
||||
$output->writeln("❌ Fehler beim Löschen von Event $externalId");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$output->writeln('Export Summary:');
|
||||
$output->writeln('----------------');
|
||||
$output->writeln('Date: ' . date('Y-m-d H:i:s'));
|
||||
$output->writeln("Number of exported events: $exportCount");
|
||||
$output->writeln("Number of deleted events: $deletedCount");
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace Mummert\KsNossenerlandBundle\Command;
|
||||
|
||||
use Contao\CoreBundle\Framework\ContaoFramework;
|
||||
use Contao\FilesModel;
|
||||
use Contao\Database;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class ExportEventsJsonCommand extends Command
|
||||
{
|
||||
private ContaoFramework $framework;
|
||||
|
||||
public function __construct(ContaoFramework $framework)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->framework = $framework;
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDescription('Exportiert Events mit export=1 und published=1 als JSON-Datei.')
|
||||
->setHelp('Dieser Command exportiert alle Events, die für den Export und die Veröffentlichung markiert sind.');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
// Contao Framework initialisieren
|
||||
$this->framework->initialize();
|
||||
|
||||
$db = Database::getInstance();
|
||||
|
||||
// Events abrufen
|
||||
$events = $db->prepare("
|
||||
SELECT id, addTime, addImage, title, startTime, endTime, startDate, endDate, description, teaser, singleSRC, external_location, alias
|
||||
FROM tl_calendar_events
|
||||
WHERE export = 1 AND published = 1
|
||||
")->execute()->fetchAllAssoc();
|
||||
|
||||
if (empty($events)) {
|
||||
$io->warning('Keine Events mit export=1 und published=1 gefunden.');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$baseUrl = 'https://kirchspiel-nossener-land.de'; // Basis-URL deiner Website
|
||||
|
||||
// Events verarbeiten
|
||||
foreach ($events as &$event) {
|
||||
// singleSRC: UUID in vollständige URL umwandeln
|
||||
if (!empty($event['singleSRC'])) {
|
||||
$file = FilesModel::findByUuid($event['singleSRC']);
|
||||
if ($file) {
|
||||
$event['singleSRC'] = $baseUrl . '/' . $file->path;
|
||||
} else {
|
||||
$event['singleSRC'] = null; // Setze auf null, falls die Datei nicht gefunden wurde
|
||||
}
|
||||
}
|
||||
|
||||
// alias: sicherstellen, dass ein Alias vorhanden ist
|
||||
if (empty($event['alias'])) {
|
||||
$event['alias'] = strtolower(preg_replace('/[^a-z0-9]+/', '-', trim($event['title']))) . '-' . date('Y-m-d', $event['startDate']);
|
||||
}
|
||||
|
||||
// Zusätzliche Transformationen (falls nötig) hier einfügen
|
||||
}
|
||||
|
||||
// JSON erstellen
|
||||
$json = json_encode($events, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
|
||||
// JSON-Datei speichern
|
||||
$filePath = '/srv/www/ks-nossener-land/public/kirchspiel-nossener-land.de/public/events.json';
|
||||
file_put_contents($filePath, $json);
|
||||
|
||||
$io->success("Export erfolgreich! Datei gespeichert unter: $filePath");
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mummert\KsNossenerlandBundle\Contao\Manager;
|
||||
|
||||
use Contao\CalendarBundle\ContaoCalendarBundle;
|
||||
use Contao\CoreBundle\ContaoCoreBundle;
|
||||
use Contao\ManagerPlugin\Bundle\BundlePluginInterface;
|
||||
use Contao\ManagerPlugin\Bundle\Config\BundleConfig;
|
||||
use Contao\ManagerPlugin\Bundle\Parser\ParserInterface;
|
||||
use Mummert\KsNossenerlandBundle\KsNossenerlandBundle;
|
||||
|
||||
class Plugin implements BundlePluginInterface
|
||||
{
|
||||
public function getBundles(ParserInterface $parser): iterable
|
||||
{
|
||||
return [
|
||||
BundleConfig::create(KsNossenerlandBundle::class)
|
||||
->setLoadAfter([ContaoCoreBundle::class, ContaoCalendarBundle::class]),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace Mummert\KsNossenerlandBundle\DataContainer;
|
||||
|
||||
use Contao\Database;
|
||||
use Contao\Date;
|
||||
use Contao\StringUtil;
|
||||
use Contao\System;
|
||||
use Contao\Calendar;
|
||||
use Contao\Config;
|
||||
|
||||
class CalendarEvents
|
||||
{
|
||||
public function listEvents($arrRow)
|
||||
{
|
||||
$database = Database::getInstance();
|
||||
|
||||
// Ortstitel aus `ctlg_orte`-Tabelle holen
|
||||
$ort = $database->prepare("SELECT ortTitle FROM ctlg_orte WHERE id=?")
|
||||
->execute($arrRow['catalog_ort'])
|
||||
->fetchAssoc();
|
||||
|
||||
$ortTitle = $ort ? $ort['ortTitle'] : '-';
|
||||
|
||||
// Event-Datum formatieren
|
||||
$span = Calendar::calculateSpan($arrRow['startTime'], $arrRow['endTime']);
|
||||
|
||||
if ($span > 0) {
|
||||
$date = Date::parse(Config::get(($arrRow['addTime'] ? 'datimFormat' : 'dateFormat')), $arrRow['startTime']) .
|
||||
$GLOBALS['TL_LANG']['MSC']['cal_timeSeparator'] .
|
||||
Date::parse(Config::get(($arrRow['addTime'] ? 'datimFormat' : 'dateFormat')), $arrRow['endTime']);
|
||||
} elseif ($arrRow['startTime'] == $arrRow['endTime']) {
|
||||
$date = Date::parse(Config::get('dateFormat'), $arrRow['startTime']) .
|
||||
($arrRow['addTime'] ? ' ' . Date::parse(Config::get('timeFormat'), $arrRow['startTime']) : '');
|
||||
} else {
|
||||
$date = Date::parse(Config::get('dateFormat'), $arrRow['startTime']) .
|
||||
($arrRow['addTime'] ? ' ' . Date::parse(Config::get('timeFormat'), $arrRow['startTime']) .
|
||||
$GLOBALS['TL_LANG']['MSC']['cal_timeSeparator'] .
|
||||
Date::parse(Config::get('timeFormat'), $arrRow['endTime']) : '');
|
||||
}
|
||||
|
||||
// Rückgabe ohne <strong>-Tag
|
||||
return '<div class="tl_content_left">' .
|
||||
$arrRow['title'] .
|
||||
' <span style="color:#999;padding-left:3px">[' . $ortTitle . ' ' . $date . ']</span>' .
|
||||
'</div>';
|
||||
}
|
||||
|
||||
public function getCtlgOrteOptions(): array
|
||||
{
|
||||
$options = [];
|
||||
$result = Database::getInstance()->prepare("SELECT id, ortTitle FROM ctlg_orte ORDER BY ortTitle")->execute();
|
||||
|
||||
while ($result->next()) {
|
||||
$options[$result->id] = $result->ortTitle;
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
public function getCtlgPfarrbereicheOptions(): array
|
||||
{
|
||||
$options = [];
|
||||
|
||||
// Daten aus ctlg_districts sortiert nach districtsTitle laden
|
||||
$result = Database::getInstance()->prepare("
|
||||
SELECT id, districtsTitle
|
||||
FROM ctlg_districts
|
||||
ORDER BY districtsTitle
|
||||
")->execute();
|
||||
|
||||
while ($result->next()) {
|
||||
$options[$result->id] = $result->districtsTitle;
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
|
||||
public function getCtlgKontaktOptions(): array
|
||||
{
|
||||
$options = [];
|
||||
|
||||
// Sortierung nach lastname, contactsTerm, firstname
|
||||
$result = Database::getInstance()->prepare("
|
||||
SELECT id, contactsTerm, contactsFirstname, contactsLastname, contactsFunction
|
||||
FROM ctlg_contacts
|
||||
ORDER BY contactsLastname, contactsTerm, contactsFirstname
|
||||
")->execute();
|
||||
|
||||
while ($result->next()) {
|
||||
// Aufbau des Labels
|
||||
if (empty($result->contactsLastname) && empty($result->contactsFirstname)) {
|
||||
// Wenn lastname und firstname fehlen
|
||||
$label = $result->contactsTerm;
|
||||
} else {
|
||||
// Wenn lastname oder firstname vorhanden
|
||||
$label = $result->contactsLastname;
|
||||
|
||||
if (!empty($result->contactsFirstname)) {
|
||||
$label .= ', ' . $result->contactsFirstname;
|
||||
}
|
||||
|
||||
if (!empty($result->contactsFunction)) {
|
||||
$label .= ' (' . $result->contactsFunction . ')';
|
||||
}
|
||||
}
|
||||
|
||||
// Nur Labels hinzufügen, die tatsächlich Werte haben
|
||||
if (!empty($label)) {
|
||||
$options[$result->id] = $label;
|
||||
}
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mummert\KsNossenerlandBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Extension\Extension;
|
||||
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
|
||||
|
||||
class KsNossenerlandExtension extends Extension
|
||||
{
|
||||
public function load(array $configs, ContainerBuilder $container): void
|
||||
{
|
||||
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../../config'));
|
||||
$loader->load('services.yml');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace Mummert\KsNossenerlandBundle\EventListener;
|
||||
|
||||
use Contao\Database;
|
||||
use Contao\DataContainer;
|
||||
use Contao\StringUtil;
|
||||
|
||||
class CalendarAliasListener
|
||||
{
|
||||
public function onSubmitCallback($dc): void
|
||||
{
|
||||
// Sicherstellen, dass der Callback mit einem gültigen DataContainer aufgerufen wurde
|
||||
if (!$dc instanceof DataContainer || !$dc->id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Event-Daten aus der Datenbank holen
|
||||
$event = Database::getInstance()
|
||||
->prepare("SELECT title, catalog_ort, startDate FROM tl_calendar_events WHERE id=?")
|
||||
->execute($dc->id)
|
||||
->fetchAssoc();
|
||||
|
||||
if (!$event) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sicherstellen, dass startDate nicht 0 ist
|
||||
$startDate = (int) $event['startDate'];
|
||||
if ($startDate <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Event-Titel und Ort holen und verarbeiten
|
||||
$title = $this->replaceUmlauts($event['title']);
|
||||
$ortTitle = $this->getOrtTitle($event['catalog_ort']);
|
||||
$date = date('Y-m-d', $startDate);
|
||||
|
||||
// Kürzen und Alias generieren
|
||||
$shortTitle = $this->shortenTitle($title, 25);
|
||||
$shortOrt = $this->shortenTitle($ortTitle, 20);
|
||||
$baseAlias = StringUtil::generateAlias("$shortTitle-$shortOrt-$date");
|
||||
|
||||
// Falls Alias bereits existiert: Zahl anhängen (-1, -2, -3 ...)
|
||||
$finalAlias = $this->getUniqueAlias($baseAlias, $dc->id);
|
||||
|
||||
// Alias direkt in der Datenbank speichern
|
||||
Database::getInstance()
|
||||
->prepare("UPDATE tl_calendar_events SET alias=? WHERE id=?")
|
||||
->execute($finalAlias, $dc->id);
|
||||
}
|
||||
|
||||
private function getOrtTitle(int $catalogOrtId): string
|
||||
{
|
||||
$result = Database::getInstance()
|
||||
->prepare("SELECT ortTitle FROM ctlg_orte WHERE id=?")
|
||||
->execute($catalogOrtId);
|
||||
|
||||
return $this->replaceUmlauts($result->ortTitle);
|
||||
}
|
||||
|
||||
private function replaceUmlauts(string $text): string
|
||||
{
|
||||
$umlauts = [
|
||||
'ä' => 'ae', 'ö' => 'oe', 'ü' => 'ue',
|
||||
'Ä' => 'Ae', 'Ö' => 'Oe', 'Ü' => 'Ue', 'ß' => 'ss'
|
||||
];
|
||||
return str_replace(array_keys($umlauts), array_values($umlauts), $text);
|
||||
}
|
||||
|
||||
private function shortenTitle(string $title, int $maxLength): string
|
||||
{
|
||||
if (mb_strlen($title) <= $maxLength) {
|
||||
return StringUtil::generateAlias($title);
|
||||
}
|
||||
|
||||
$words = explode(' ', $title);
|
||||
$shortTitle = '';
|
||||
|
||||
foreach ($words as $word) {
|
||||
if (mb_strlen($shortTitle . ' ' . $word) > $maxLength) {
|
||||
break;
|
||||
}
|
||||
$shortTitle .= (empty($shortTitle) ? '' : '-') . $word;
|
||||
}
|
||||
|
||||
return StringUtil::generateAlias($shortTitle);
|
||||
}
|
||||
|
||||
private function getUniqueAlias(string $baseAlias, int $eventId): string
|
||||
{
|
||||
$db = Database::getInstance();
|
||||
$alias = $baseAlias;
|
||||
$counter = 1;
|
||||
|
||||
while ($db->prepare("SELECT id FROM tl_calendar_events WHERE alias=? AND id!=?")
|
||||
->execute($alias, $eventId)->numRows > 0) {
|
||||
$alias = $baseAlias . '-' . $counter;
|
||||
$counter++;
|
||||
}
|
||||
|
||||
return $alias;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace Mummert\KsNossenerlandBundle\EventListener;
|
||||
|
||||
use Contao\CoreBundle\ServiceAnnotation\Hook;
|
||||
use Contao\Template;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Contao\StringUtil;
|
||||
|
||||
class EventFullListener
|
||||
{
|
||||
private Connection $connection;
|
||||
private LoggerInterface $logger;
|
||||
|
||||
public function __construct(Connection $connection, LoggerInterface $logger)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Hook("parseTemplate")
|
||||
*/
|
||||
public function onParseTemplate(Template $template): void
|
||||
{
|
||||
if ($template->getName() !== 'event_full') {
|
||||
return;
|
||||
}
|
||||
|
||||
$ortId = (int) ($template->external_location ?? 0);
|
||||
|
||||
$template->eventPlace = '';
|
||||
$template->eventAlias = '';
|
||||
$template->eventLatitude = '';
|
||||
$template->eventLongitude = '';
|
||||
$template->eventDistricts = [];
|
||||
|
||||
// Veranstaltungsort-Daten laden
|
||||
if ($ortId > 0) {
|
||||
$ort = $this->connection->fetchAssociative('SELECT * FROM ctlg_orte WHERE id = ?', [$ortId]);
|
||||
|
||||
if ($ort) {
|
||||
$template->eventPlace = $ort['ortTitle'] ?? '';
|
||||
$template->eventAlias = $ort['alias'] ?? '';
|
||||
$template->eventLatitude = $ort['ortLatitude'] ?? '';
|
||||
$template->eventLongitude = $ort['ortLongitude'] ?? '';
|
||||
|
||||
$gemeindeId = $ort['ortGemeinde'] ?? null;
|
||||
|
||||
if ($gemeindeId) {
|
||||
$gemeinde = $this->connection->fetchAssociative('SELECT * FROM ctlg_gemeinden WHERE id = ?', [$gemeindeId]);
|
||||
|
||||
if ($gemeinde && !empty($gemeinde['gemeindeBereich'])) {
|
||||
$district = $this->connection->fetchAssociative('SELECT * FROM ctlg_districts WHERE id = ?', [$gemeinde['gemeindeBereich']]);
|
||||
|
||||
if ($district) {
|
||||
$template->eventDistricts[] = [
|
||||
'gemeindeTitel' => $gemeinde['gemeindeTitel'],
|
||||
'title' => $district['districtsTitle'],
|
||||
'alias' => $district['districtsAlias'],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace Mummert\KsNossenerlandBundle\EventListener;
|
||||
|
||||
use Contao\Template;
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
class EventJsonDataListener
|
||||
{
|
||||
private static $jsonData = null; // Statische Variable, um die JSON-Daten zu cachen
|
||||
private string $jsonUrl;
|
||||
private Client $httpClient;
|
||||
|
||||
public function __construct(Client $httpClient, string $jsonUrl)
|
||||
{
|
||||
$this->httpClient = $httpClient;
|
||||
$this->jsonUrl = $jsonUrl;
|
||||
}
|
||||
|
||||
public function onParseTemplate(Template $template): void
|
||||
{
|
||||
// Unterstützte Templates
|
||||
$supportedTemplates = ['event_full', 'event_upcoming_all'];
|
||||
|
||||
// Nur für unterstützte Templates ausführen
|
||||
if (!in_array($template->getName(), $supportedTemplates, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Lade die JSON-Daten (nur einmal)
|
||||
if (self::$jsonData === null) {
|
||||
self::$jsonData = $this->fetchJsonData();
|
||||
}
|
||||
|
||||
// JSON-Daten sind nicht verfügbar
|
||||
if (self::$jsonData === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Event-Datum auslesen (als `start` im JSON)
|
||||
$eventDate = $template->startDate ? date('Y-m-d', $template->startDate) : null;
|
||||
|
||||
if (!$eventDate) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Passenden Datensatz anhand des Datums suchen
|
||||
$eventData = array_filter(self::$jsonData, fn($event) => $event['start'] === $eventDate);
|
||||
|
||||
if (!$eventData) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Daten ans Template übergeben
|
||||
$template->jsonEventData = reset($eventData);
|
||||
}
|
||||
|
||||
private function fetchJsonData(): ?array
|
||||
{
|
||||
try {
|
||||
$response = $this->httpClient->request('GET', $this->jsonUrl, [
|
||||
'timeout' => 3.0,
|
||||
'connect_timeout' => 2.0,
|
||||
'http_errors' => false,
|
||||
]);
|
||||
|
||||
if (200 !== $response->getStatusCode()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$json = (string) $response->getBody();
|
||||
return $json ? json_decode($json, true) : null;
|
||||
} catch (\Exception $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
namespace Mummert\KsNossenerlandBundle\EventListener;
|
||||
|
||||
use Contao\CalendarEventsModel;
|
||||
use Contao\CoreBundle\DependencyInjection\Attribute\AsHook;
|
||||
use Kigkonsult\Icalcreator\Vevent;
|
||||
use Contao\System;
|
||||
use Doctrine\DBAL\Connection;
|
||||
|
||||
#[AsHook('editVEvent')]
|
||||
class ModifyIcalDataListener
|
||||
{
|
||||
private Connection $connection;
|
||||
|
||||
public function __construct(Connection $connection)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
public function __invoke(Vevent $vEvent, CalendarEventsModel $objEvent): Vevent
|
||||
{
|
||||
// Loggen, ob der Listener getriggert wird
|
||||
System::getContainer()->get('monolog.logger.contao')->info(
|
||||
'ModifyIcalDataListener triggered for event ID ' . $objEvent->id
|
||||
);
|
||||
|
||||
// Zeitzone setzen
|
||||
if (!empty($objEvent->startTime)) {
|
||||
$startDate = (new \DateTime())->setTimestamp($objEvent->startTime)->setTimezone(new \DateTimeZone('Europe/Berlin'));
|
||||
$vEvent->setDtstart($startDate);
|
||||
}
|
||||
|
||||
// Beschreibung (teaser) setzen, HTML-Tags entfernen
|
||||
$description = strip_tags($objEvent->teaser);
|
||||
|
||||
// Zusätzlicher Beschreibungstext für Kontakte & Contributors
|
||||
$additionalDescription = '';
|
||||
|
||||
// Teilnehmer aus catalog_kontakt (Mehrfach-IDs) und Organisator ermitteln
|
||||
$organizerEmail = 'ksp.nossener-land@evlks.de';
|
||||
$organizerName = 'Ev.-Luth. Kirchspiel Nossener Land';
|
||||
|
||||
if (!empty($objEvent->catalog_kontakt)) {
|
||||
$contactIds = array_filter(array_map('trim', explode(',', $objEvent->catalog_kontakt)));
|
||||
|
||||
if (!empty($contactIds)) {
|
||||
$query = $this->connection->createQueryBuilder()
|
||||
->select('contactsTerm', 'contactsFirstname', 'contactsLastname', 'contactsEmail')
|
||||
->from('ctlg_contacts')
|
||||
->where('id IN (:ids)')
|
||||
->setParameter('ids', $contactIds, Connection::PARAM_INT_ARRAY)
|
||||
->executeQuery();
|
||||
|
||||
$contacts = $query->fetchAllAssociative();
|
||||
|
||||
$contactStrings = [];
|
||||
foreach ($contacts as $index => $contact) {
|
||||
$contactName = trim("{$contact['contactsTerm']} {$contact['contactsFirstname']} {$contact['contactsLastname']}");
|
||||
if (!empty($contactName)) {
|
||||
$contactStrings[] = $contactName;
|
||||
}
|
||||
|
||||
// Falls es der erste Eintrag ist und eine E-Mail vorhanden ist, als Organisator setzen
|
||||
if ($index === 0 && !empty($contact['contactsEmail'])) {
|
||||
$organizerEmail = $contact['contactsEmail'];
|
||||
$organizerName = $contactName;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($contactStrings)) {
|
||||
$additionalDescription .= "mit " . implode("\n", $contactStrings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Falls das Feld contributors ausgefüllt ist, ebenfalls hinzufügen
|
||||
if (!empty($objEvent->contributors)) {
|
||||
$contributorList = array_map('trim', explode(',', $objEvent->contributors));
|
||||
if (!empty($contributorList)) {
|
||||
$additionalDescription .= "mit " . implode("\n", $contributorList);
|
||||
}
|
||||
}
|
||||
|
||||
// Falls teaser bereits existiert, trennen wir die zusätzlichen Infos mit einem Zeilenumbruch
|
||||
if (!empty($description) && !empty($additionalDescription)) {
|
||||
$description .= "\n\n" . $additionalDescription;
|
||||
} elseif (!empty($additionalDescription)) {
|
||||
$description = $additionalDescription;
|
||||
}
|
||||
|
||||
// Beschreibung setzen
|
||||
$vEvent->setDescription($description);
|
||||
|
||||
// LOCATION und GEO aus ctlg_orte abrufen
|
||||
if (!empty($objEvent->catalog_ort)) {
|
||||
$query = $this->connection->createQueryBuilder()
|
||||
->select('ortTitle', 'ortLatitude', 'ortLongitude')
|
||||
->from('ctlg_orte')
|
||||
->where('id = :id')
|
||||
->setParameter('id', $objEvent->catalog_ort)
|
||||
->executeQuery();
|
||||
|
||||
$locationData = $query->fetchAssociative();
|
||||
|
||||
if ($locationData) {
|
||||
$vEvent->setLocation($locationData['ortTitle']);
|
||||
|
||||
if (!empty($locationData['ortLatitude']) && !empty($locationData['ortLongitude'])) {
|
||||
$vEvent->setGeo($locationData['ortLatitude'], $locationData['ortLongitude']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ORGANIZER setzen
|
||||
$vEvent->setOrganizer("mailto:{$organizerEmail}", ['CN' => $organizerName]);
|
||||
|
||||
return $vEvent;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
<?php
|
||||
|
||||
namespace Mummert\KsNossenerlandBundle\EventListener;
|
||||
|
||||
use Contao\CoreBundle\ServiceAnnotation\Hook;
|
||||
use Contao\Template;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Contao\StringUtil;
|
||||
|
||||
class OfferListener
|
||||
{
|
||||
private LoggerInterface $logger;
|
||||
private Connection $connection;
|
||||
|
||||
public function __construct(LoggerInterface $logger, Connection $connection)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Hook("parseTemplate")
|
||||
*/
|
||||
public function onParseTemplate(Template $template): void
|
||||
{
|
||||
// Einzelansicht
|
||||
if ($template->getName() === 'cm_master_angebote') {
|
||||
$angebotId = $template->id;
|
||||
|
||||
$angebot = $this->connection->fetchAssociative('SELECT * FROM ctlg_angebote WHERE id = ?', [$angebotId]);
|
||||
|
||||
if ($angebot) {
|
||||
$gemeindeIds = StringUtil::deserialize($angebot['angebotGemeinde'], true);
|
||||
$gemeinden = [];
|
||||
|
||||
if (!empty($gemeindeIds)) {
|
||||
$gemeindenRaw = $this->connection->fetchAllAssociative(
|
||||
'SELECT * FROM ctlg_gemeinden WHERE id IN (?)',
|
||||
[$gemeindeIds],
|
||||
[Connection::PARAM_INT_ARRAY]
|
||||
);
|
||||
|
||||
foreach ($gemeindenRaw as $gemeinde) {
|
||||
$bereichId = $gemeinde['gemeindeBereich'] ?? null;
|
||||
$district = null;
|
||||
|
||||
if ($bereichId) {
|
||||
$districtRaw = $this->connection->fetchAssociative(
|
||||
'SELECT * FROM ctlg_districts WHERE id = ?',
|
||||
[$bereichId]
|
||||
);
|
||||
|
||||
if ($districtRaw) {
|
||||
$district = [
|
||||
'id' => $bereichId,
|
||||
'title' => $districtRaw['districtsTitle'],
|
||||
'alias' => $districtRaw['districtsAlias'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$gemeinden[] = [
|
||||
'titel' => $gemeinde['gemeindeTitel'],
|
||||
'einheit' => $gemeinde['gemeindeEinheit'],
|
||||
'district' => $district,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$template->angebotGemeinden = $gemeinden;
|
||||
}
|
||||
}
|
||||
|
||||
// Kontaktansicht
|
||||
if ($template->getName() === 'cm_master_contacts') {
|
||||
$currentContactId = $template->id;
|
||||
|
||||
$angebote = $this->connection->fetchAllAssociative('SELECT * FROM ctlg_angebote');
|
||||
$filteredOffers = [];
|
||||
|
||||
foreach ($angebote as $angebot) {
|
||||
$angebotContacts = StringUtil::deserialize($angebot['angeboteContacts']);
|
||||
if (is_array($angebotContacts) && in_array($currentContactId, $angebotContacts)) {
|
||||
$gemeindeIds = StringUtil::deserialize($angebot['angebotGemeinde'], true);
|
||||
$gemeinden = [];
|
||||
|
||||
if (!empty($gemeindeIds)) {
|
||||
$gemeindenRaw = $this->connection->fetchAllAssociative(
|
||||
'SELECT * FROM ctlg_gemeinden WHERE id IN (?)',
|
||||
[$gemeindeIds],
|
||||
[Connection::PARAM_INT_ARRAY]
|
||||
);
|
||||
|
||||
foreach ($gemeindenRaw as $gemeinde) {
|
||||
$bereichId = $gemeinde['gemeindeBereich'] ?? null;
|
||||
$district = null;
|
||||
|
||||
if ($bereichId) {
|
||||
$districtRaw = $this->connection->fetchAssociative(
|
||||
'SELECT * FROM ctlg_districts WHERE id = ?',
|
||||
[$bereichId]
|
||||
);
|
||||
|
||||
if ($districtRaw) {
|
||||
$district = [
|
||||
'id' => $bereichId,
|
||||
'title' => $districtRaw['districtsTitle'],
|
||||
'alias' => $districtRaw['districtsAlias'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$gemeinden[] = [
|
||||
'titel' => $gemeinde['gemeindeTitel'],
|
||||
'einheit' => $gemeinde['gemeindeEinheit'],
|
||||
'district' => $district,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$angebot['angebotGemeinden'] = $gemeinden;
|
||||
$angebot['angebotGemeindeIds'] = $gemeindeIds;
|
||||
|
||||
// Nur Aliase extrahieren
|
||||
$angebot['angebotDistrictIds'] = array_values(array_unique(array_map(
|
||||
fn($g) => $g['district']['alias'] ?? null,
|
||||
array_filter($gemeinden, fn($g) => !empty($g['district']['alias']))
|
||||
)));
|
||||
|
||||
$filteredOffers[] = $angebot;
|
||||
}
|
||||
}
|
||||
|
||||
$orte = $this->connection->fetchAllAssociative('SELECT * FROM ctlg_orte');
|
||||
$filteredOrte = [];
|
||||
|
||||
foreach ($orte as $ort) {
|
||||
$orteContacts = StringUtil::deserialize($ort['ortContacts']);
|
||||
if (is_array($orteContacts) && in_array($currentContactId, $orteContacts)) {
|
||||
|
||||
$ortDistrictTitles = [];
|
||||
|
||||
$gemeindeId = (int) $ort['ortGemeinde'];
|
||||
if ($gemeindeId > 0) {
|
||||
$bereichId = $this->connection->fetchOne(
|
||||
'SELECT gemeindeBereich FROM ctlg_gemeinden WHERE id = ?',
|
||||
[$gemeindeId]
|
||||
);
|
||||
|
||||
if ($bereichId) {
|
||||
$title = $this->connection->fetchOne(
|
||||
'SELECT districtsTitle FROM ctlg_districts WHERE id = ?',
|
||||
[$bereichId]
|
||||
);
|
||||
|
||||
if ($title) {
|
||||
$ortDistrictTitles[] = $title;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ort['orteDistrictsTitles'] = $ortDistrictTitles;
|
||||
$filteredOrte[] = $ort;
|
||||
}
|
||||
}
|
||||
|
||||
$template->angebote = $filteredOffers;
|
||||
$template->orte = $filteredOrte;
|
||||
}
|
||||
|
||||
// Listenansicht
|
||||
if ($template->getName() === 'cm_listing_angebote') {
|
||||
$raw = StringUtil::deserialize($template->angebotGemeinde, true);
|
||||
$gemeindeIds = [];
|
||||
|
||||
foreach ($raw as $item) {
|
||||
if (is_array($item) && isset($item['value'])) {
|
||||
$gemeindeIds[] = (string) $item['value'];
|
||||
} elseif (is_scalar($item)) {
|
||||
$gemeindeIds[] = (string) $item;
|
||||
}
|
||||
}
|
||||
|
||||
$template->angebotGemeindeIds = $gemeindeIds;
|
||||
|
||||
// Gemeindebezogene Aliase der Districts laden
|
||||
$districtIds = [];
|
||||
|
||||
if (!empty($gemeindeIds)) {
|
||||
$rows = $this->connection->fetchAllAssociative(
|
||||
'SELECT g.gemeindeBereich, d.districtsAlias
|
||||
FROM ctlg_gemeinden g
|
||||
LEFT JOIN ctlg_districts d ON g.gemeindeBereich = d.id
|
||||
WHERE g.id IN (?)',
|
||||
[$gemeindeIds],
|
||||
[Connection::PARAM_INT_ARRAY]
|
||||
);
|
||||
|
||||
foreach ($rows as $row) {
|
||||
if (!empty($row['districtsAlias'])) {
|
||||
$districtIds[] = $row['districtsAlias'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$template->angebotDistrictIds = array_values(array_unique($districtIds));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Mummert\KsNossenerlandBundle\EventListener;
|
||||
|
||||
use Contao\CoreBundle\ServiceAnnotation\Hook;
|
||||
use Contao\Template;
|
||||
use Contao\StringUtil;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class PlaceListener
|
||||
{
|
||||
private LoggerInterface $logger;
|
||||
private Connection $connection;
|
||||
|
||||
public function __construct(LoggerInterface $logger, Connection $connection)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Hook("parseTemplate")
|
||||
*/
|
||||
public function onParseTemplate(Template $template): void
|
||||
{
|
||||
// Nur für Template cm_listing_orte.html5
|
||||
if ($template->getName() !== 'cm_listing_orte') {
|
||||
return;
|
||||
}
|
||||
|
||||
$gemeindenRaw = StringUtil::deserialize($template->ortGemeinde, true);
|
||||
|
||||
// Gemeindelisten extrahieren
|
||||
$gemeindeIds = array_map(function ($item) {
|
||||
if (is_array($item) && isset($item['value'])) {
|
||||
return (string) $item['value'];
|
||||
}
|
||||
return (string) $item;
|
||||
}, $gemeindenRaw);
|
||||
|
||||
$template->ortGemeindeIds = $gemeindeIds;
|
||||
|
||||
// Passende District-Aliase ermitteln
|
||||
$districtAliases = [];
|
||||
|
||||
if (!empty($gemeindeIds)) {
|
||||
$rows = $this->connection->fetchAllAssociative(
|
||||
'SELECT d.districtsAlias
|
||||
FROM ctlg_gemeinden g
|
||||
LEFT JOIN ctlg_districts d ON g.gemeindeBereich = d.id
|
||||
WHERE g.id IN (?)',
|
||||
[$gemeindeIds],
|
||||
[Connection::PARAM_INT_ARRAY]
|
||||
);
|
||||
|
||||
foreach ($rows as $row) {
|
||||
if (!empty($row['districtsAlias'])) {
|
||||
$districtAliases[] = (string) $row['districtsAlias'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$template->ortDistrictIds = array_values(array_unique($districtAliases));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mummert\KsNossenerlandBundle;
|
||||
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
|
||||
class KsNossenerlandBundle extends Bundle
|
||||
{
|
||||
public function getPath(): string
|
||||
{
|
||||
return dirname(__DIR__);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Mummert\KsNossenerlandBundle\Model;
|
||||
|
||||
use PDO;
|
||||
|
||||
class ExternalLocationModel
|
||||
{
|
||||
/**
|
||||
* Erstellt die PDO-Verbindung zur externen Datenbank.
|
||||
*
|
||||
* @return PDO
|
||||
*/
|
||||
private static function getConnection()
|
||||
{
|
||||
$dsn = getenv('KS_NOSSENERLAND_EXTERNAL_DB_DSN') ?: '';
|
||||
$user = getenv('KS_NOSSENERLAND_EXTERNAL_DB_USER') ?: '';
|
||||
$password = getenv('KS_NOSSENERLAND_EXTERNAL_DB_PASSWORD') ?: '';
|
||||
|
||||
if ('' === $dsn || '' === $user) {
|
||||
throw new \PDOException('Missing external DB env vars for location lookup.');
|
||||
}
|
||||
|
||||
return new PDO(
|
||||
$dsn,
|
||||
$user,
|
||||
$password,
|
||||
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Holt alle Einträge aus der Tabelle 'tl_location' und sortiert sie nach title (A-Z).
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function findAllLocations()
|
||||
{
|
||||
try {
|
||||
$pdo = self::getConnection();
|
||||
|
||||
// Alphabetisch nach `title` sortieren
|
||||
$stmt = $pdo->query('SELECT id, title FROM tl_location ORDER BY title ASC');
|
||||
$locations = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
if (empty($locations)) {
|
||||
error_log("Die Tabelle 'tl_location' ist leer.");
|
||||
} else {
|
||||
foreach ($locations as $location) {
|
||||
error_log("Gefundene Location: ID={$location['id']}, Title={$location['title']}");
|
||||
}
|
||||
}
|
||||
|
||||
return $locations;
|
||||
} catch (\PDOException $e) {
|
||||
error_log("PDO-Fehler: " . $e->getMessage());
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
<?php
|
||||
|
||||
namespace Mummert\KsNossenerlandBundle\Service;
|
||||
|
||||
use SoapClient;
|
||||
use SoapHeader;
|
||||
use Exception;
|
||||
use StdClass;
|
||||
use Doctrine\DBAL\Connection;
|
||||
|
||||
class SoapClientService
|
||||
{
|
||||
private ?SoapClient $client = null;
|
||||
private string $apiKey;
|
||||
private string $vid;
|
||||
private Connection $connection;
|
||||
|
||||
public function __construct(Connection $connection, string $wsdlUrl, string $endpointUrl, string $apiKey, string $vid)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
$this->apiKey = $apiKey;
|
||||
$this->vid = $vid;
|
||||
|
||||
if ('' === trim($this->apiKey) || '' === trim($this->vid)) {
|
||||
error_log('SOAP Client initialization skipped: missing API key or vid.');
|
||||
return;
|
||||
}
|
||||
|
||||
$options = [
|
||||
'location' => $endpointUrl,
|
||||
'trace' => false,
|
||||
'exception' => true,
|
||||
];
|
||||
|
||||
try {
|
||||
$this->client = new SoapClient($wsdlUrl, $options);
|
||||
$auth = new StdClass;
|
||||
$auth->apiKey = $this->apiKey;
|
||||
$auth->vid = $this->vid;
|
||||
$header = new SoapHeader($endpointUrl, "APIValidate", $auth);
|
||||
$this->client->__setSoapHeaders($header);
|
||||
} catch (Exception $e) {
|
||||
error_log('SOAP Client initialization failed: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private function getEventTypeByPid($pid)
|
||||
{
|
||||
return match ($pid) {
|
||||
1 => '1',
|
||||
2 => '4',
|
||||
3 => '9',
|
||||
default => '9',
|
||||
};
|
||||
}
|
||||
|
||||
private function transformEventData(array $eventData): array
|
||||
{
|
||||
// ggf. verkürzt für Übersichtlichkeit – hier bleibt deine Mapping-Logik erhalten
|
||||
$placeIdMapping = [
|
||||
65 => 4694, // Diakoniestation Dittmannsdorf
|
||||
61 => 4695, // Ev. Kindergarten Dittmannsdorf
|
||||
53 => 4699, // Friedhof Bieberstein
|
||||
52 => 4678, // Friedhof Burkhardswalde
|
||||
51 => 4672, // Friedhof Deutschenbora
|
||||
50 => 4696, // Friedhof Dittmannsdorf
|
||||
49 => 4681, // Friedhof Heynitz
|
||||
48 => 4702, // Friedhof Hirschfeld
|
||||
47 => 4685, // Friedhof Krögis
|
||||
34 => 4660, // Friedhof Leuben
|
||||
81 => 4688, // Friedhof Miltitz
|
||||
46 => 4706, // Friedhof Neukirchen
|
||||
44 => 4667, // Friedhof Nossen
|
||||
43 => 4709, // Friedhof Obergruna
|
||||
36 => 4663, // Friedhof Planitz
|
||||
31 => 4656, // Friedhof Raußlitz
|
||||
42 => 4712, // Friedhof Reinsberg
|
||||
41 => 4675, // Friedhof Rothschönberg
|
||||
33 => 4648, // Friedhof Rüsseina
|
||||
39 => 4715, // Friedhof Siebenlehn
|
||||
38 => 4690, // Friedhof Tanneberg
|
||||
37 => 4692, // Friedhof Taubenheim
|
||||
30 => 4651, // Friedhof Wendischbora
|
||||
35 => 4665, // Friedhof Ziegenhain
|
||||
45 => 4668, // Friedhofskapelle Nossen
|
||||
68 => 4673, // Gemeindehaus Deutschenbora
|
||||
27 => 4652, // Gemeindehaus Wendischbora
|
||||
73 => 4700, // Gemeinderaum Bieberstein
|
||||
71 => 4697, // Gemeinderaum Dittmannsdorf
|
||||
63 => 4682, // Gemeinderaum Heynitz
|
||||
77 => 4703, // Gemeinderaum Hirschfeld
|
||||
55 => 4686, // Gemeinderaum in der Kirche Krögis
|
||||
78 => 4707, // Gemeinderaum Neukirchen
|
||||
67 => 4669, // Gemeinderaum Nossen
|
||||
72 => 4710, // Gemeinderaum Obergruna
|
||||
26 => 4657, // Gemeinderaum Raußlitz
|
||||
75 => 4713, // Gemeinderaum Reinsberg
|
||||
69 => 4676, // Gemeinderaum Rothschönberg
|
||||
60 => 4716, // Gemeinderaum Siebenlehn
|
||||
28 => 4653, // Großer Gemeinderaum Wendischbora
|
||||
70 => 4719, // Heimatstube
|
||||
14 => 4701, // Kirche Bieberstein
|
||||
8 => 4679, // Kirche Burkhardswalde
|
||||
2 => 4674, // Kirche Deutschenbora
|
||||
15 => 4698, // Kirche Dittmannsdorf
|
||||
5 => 4683, // Kirche Heynitz
|
||||
22 => 4704, // Kirche Hirschfeld
|
||||
6 => 4687, // Kirche Krögis
|
||||
10 => 4661, // Kirche Leuben
|
||||
4 => 1409, // Kirche Miltitz
|
||||
16 => 4708, // Kirche Neukirchen
|
||||
1 => 4670, // Kirche Nossen
|
||||
21 => 4711, // Kirche Obergruna
|
||||
12 => 4664, // Kirche Planitz
|
||||
18 => 4658, // Kirche Raußlitz
|
||||
13 => 4714, // Kirche Reinsberg
|
||||
3 => 4677, // Kirche Rothschönberg
|
||||
17 => 4647, // Kirche Rüsseina
|
||||
20 => 4717, // Kirche Siebenlehn
|
||||
9 => 4691, // Kirche Tanneberg
|
||||
7 => 4693, // Kirche Taubenheim
|
||||
19 => 4654, // Kirche Wendischbora
|
||||
11 => 4666, // Kirche Ziegenhain
|
||||
32 => 4649, // Kirchfriedhof Rüsseina
|
||||
29 => 4655, // Kleiner Gemeinderaum Wendischbora
|
||||
83 => 4720, // Ludwig-Richter-Saal
|
||||
56 => 4680, // Pfarrhaus Burkhardswalde
|
||||
62 => 4684, // Pfarrhaus Heynitz
|
||||
74 => 4705, // Pfarrhaus Hirschfeld
|
||||
58 => 4662, // Pfarrhaus Leuben
|
||||
59 => 4689, // Pfarrhaus Miltitz
|
||||
54 => 4671, // Pfarrhaus Nossen
|
||||
25 => 4659, // Pfarrhaus Raußlitz
|
||||
23 => 4650, // Pfarrhaus Rüsseina
|
||||
76 => 4718, // Pfarrhaus Siebenlehn
|
||||
96 => 5032, // BadePark Reinsberg
|
||||
95 => 5191, // Kloster Altzella
|
||||
101 => 5508, // Schlosskapelle Rothschönberg
|
||||
|
||||
|
||||
];
|
||||
|
||||
$placeid = $placeIdMapping[$eventData['catalog_ort']] ?? null;
|
||||
$eventType = isset($eventData['pid']) ? $this->getEventTypeByPid($eventData['pid']) : '9';
|
||||
|
||||
$kontaktIds = explode(',', $eventData['catalog_kontakt'] ?? '');
|
||||
$contacts = [];
|
||||
$email = '';
|
||||
|
||||
foreach ($kontaktIds as $index => $kontaktId) {
|
||||
$kontaktId = trim($kontaktId);
|
||||
if ($kontaktId) {
|
||||
$contactData = $this->connection->fetchAssociative(
|
||||
'SELECT contactsTerm, contactsFirstname, contactsLastname, contactsEmail FROM ctlg_contacts WHERE id = ?',
|
||||
[$kontaktId]
|
||||
);
|
||||
if ($contactData) {
|
||||
$contacts[] = $contactData['contactsTerm'] . ' ' . $contactData['contactsFirstname'] . ' ' . $contactData['contactsLastname'];
|
||||
if ($index === 0 && !empty($contactData['contactsEmail'])) {
|
||||
$email = $contactData['contactsEmail'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$contributors = !empty($eventData['contributors']) ? explode(',', $eventData['contributors']) : [];
|
||||
$allPeople = array_merge($contacts, $contributors);
|
||||
$people = !empty($allPeople) ? implode(', ', $allPeople) : '';
|
||||
|
||||
return [
|
||||
'placeid' => $placeid,
|
||||
'eventType' => $eventType,
|
||||
'people' => $people,
|
||||
'email' => $email
|
||||
];
|
||||
}
|
||||
|
||||
public function sendEventToSoapAPI($eventData)
|
||||
{
|
||||
if (!$this->client instanceof SoapClient) {
|
||||
error_log('SOAP client unavailable: skipping event export for ID ' . ($eventData['id'] ?? 'unknown'));
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($eventData['published'] == '1') {
|
||||
$destination = 'extern';
|
||||
$status = 'ok';
|
||||
} else {
|
||||
$destination = 'intern';
|
||||
$status = 'standby';
|
||||
}
|
||||
|
||||
$transformed = $this->transformEventData($eventData);
|
||||
$placeid = $transformed['placeid'];
|
||||
$eventType = $transformed['eventType'];
|
||||
$people = $transformed['people'];
|
||||
$email = $transformed['email'];
|
||||
|
||||
if ($placeid === null) {
|
||||
error_log('❌ Keine gültige placeid für Event ' . $eventData['id']);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isset($eventData['addTime']) && $eventData['addTime'] == '1') {
|
||||
$start = date('Y-m-d', $eventData['startDate']) . ' ' . (!empty($eventData['startTime']) ? date('H:i:s', $eventData['startTime']) : '00:00:00');
|
||||
$end = date('Y-m-d', $eventData['endDate']) . ' ' . (!empty($eventData['endTime']) ? date('H:i:s', $eventData['endTime']) : '00:00:00');
|
||||
} else {
|
||||
$start = date('Y-m-d', $eventData['startDate']) . ' 00:00:00';
|
||||
$end = date('Y-m-d', $eventData['endDate']) . ' 00:00:00';
|
||||
}
|
||||
|
||||
$link = 'https://kirchspiel-nossener-land.de/termine/' . $eventData['alias'];
|
||||
$menue1 = (isset($eventData['godi_options']) && in_array('2', explode(',', $eventData['godi_options']))) ? 100 : null;
|
||||
|
||||
$event = [
|
||||
'externalid' => strval($eventData['id']),
|
||||
'eventexternalid' => strval($eventData['id']),
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
'title' => html_entity_decode($eventData['title'], ENT_QUOTES, 'UTF-8'),
|
||||
'inputmaskid' => 1,
|
||||
'personid' => 2001,
|
||||
'destination' => $destination,
|
||||
'placeid' => $placeid,
|
||||
'status' => $status,
|
||||
'shortdescription' => html_entity_decode(strip_tags($eventData['subtitle'] ?? ($eventData['subTitle'] ?? '')), ENT_QUOTES, 'UTF-8'),
|
||||
'longdescription' => html_entity_decode(strip_tags($eventData['teaser'] ?? ''), ENT_QUOTES, 'UTF-8'),
|
||||
'link' => $link,
|
||||
'email' => $email,
|
||||
'eventtype' => $eventType,
|
||||
'kat' => '3',
|
||||
'kat2' => null,
|
||||
'textline1' => $people,
|
||||
'people' => null,
|
||||
'menue1' => $menue1,
|
||||
'kollekte' => 0,
|
||||
];
|
||||
|
||||
try {
|
||||
return $this->client->saveEvent(array_merge(['apiKey' => $this->apiKey], $event));
|
||||
} catch (Exception $e) {
|
||||
error_log('❌ Fehler bei Export von Event ' . $eventData['id'] . ': ' . $e->getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteEventByExternalId(string $externalId): bool
|
||||
{
|
||||
if (!$this->client instanceof SoapClient) {
|
||||
error_log("SOAP client unavailable: cannot delete event $externalId");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$response = $this->client->deleteEvent($externalId, true);
|
||||
|
||||
// Optional prüfen, ob eine success-Eigenschaft existiert
|
||||
if (is_object($response) && property_exists($response, 'success')) {
|
||||
return $response->success === true;
|
||||
}
|
||||
|
||||
// Falls keine success-Eigenschaft, dann success annehmen, wenn kein Fehler auftrat
|
||||
return true;
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log("❌ Fehler beim Löschen von Event $externalId: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function fetchRemoteExternalIds(): array
|
||||
{
|
||||
$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");
|
||||
return [];
|
||||
}
|
||||
|
||||
$data = json_decode($json, true);
|
||||
if (!is_array($data)) {
|
||||
error_log("❌ Ungültiges JSON-Format für Kalenderdaten");
|
||||
return [];
|
||||
}
|
||||
|
||||
$externalIds = [];
|
||||
foreach ($data as $entry) {
|
||||
if (!empty($entry['Veranstaltung']['_event_EXTERNAL_ID'])) {
|
||||
$externalIds[] = $entry['Veranstaltung']['_event_EXTERNAL_ID'];
|
||||
}
|
||||
}
|
||||
|
||||
return $externalIds;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user