199 lines
7.0 KiB
PHP
Executable File
199 lines
7.0 KiB
PHP
Executable File
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Evomedien\Vitec\UserFunc;
|
|
|
|
use Doctrine\DBAL\ParameterType;
|
|
use TYPO3\CMS\Core\Attribute\AsAllowedCallable;
|
|
use TYPO3\CMS\Core\Database\ConnectionPool;
|
|
use TYPO3\CMS\Core\Service\FlexFormService;
|
|
use Evomedien\Vitec\Service\RteResolver;
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
|
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
|
|
|
|
/**
|
|
* UserFunc: render the VITEC locations as JSON (headless).
|
|
*
|
|
* Output under content.locations:
|
|
* { "variant": "grid|list|map", "mapText": "<p>…</p>"|null, "locations": [ … ] }
|
|
*
|
|
* Each location follows the frontend contract (id, slug, name, countryCode,
|
|
* coordinates, address, contact, links, marker, sorting, active).
|
|
*
|
|
* `render()` = top-level plugin / page discovery. `renderForRecord()` = one
|
|
* specific tt_content row (reused by ContainerChildrenProcessor for nested
|
|
* plugins). Exception-safe.
|
|
*/
|
|
class LocationsJsonRenderer
|
|
{
|
|
private const TABLE = 'tx_vitec_domain_model_location';
|
|
|
|
#[AsAllowedCallable]
|
|
public function render(string $content, array $conf): string
|
|
{
|
|
$row = is_array($this->cObj->data ?? null) ? $this->cObj->data : null;
|
|
if ($row && (string)($row['CType'] ?? '') === 'vitec_locationlist') {
|
|
return $this->renderForRecord($row);
|
|
}
|
|
|
|
$pageId = 0;
|
|
$request = $GLOBALS['TYPO3_REQUEST'] ?? null;
|
|
if ($request !== null) {
|
|
$pageInfo = $request->getAttribute('frontend.page.information');
|
|
if ($pageInfo !== null) {
|
|
$pageId = (int)$pageInfo->getId();
|
|
}
|
|
}
|
|
if ($pageId <= 0) {
|
|
$pageId = (int)($GLOBALS['TSFE']->id ?? 0);
|
|
}
|
|
if ($pageId <= 0) {
|
|
return '';
|
|
}
|
|
|
|
$qb = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
|
|
$ces = $qb
|
|
->select('*')
|
|
->from('tt_content')
|
|
->where(
|
|
$qb->expr()->eq('pid', $qb->createNamedParameter($pageId, ParameterType::INTEGER)),
|
|
$qb->expr()->eq('CType', $qb->createNamedParameter('vitec_locationlist', ParameterType::STRING)),
|
|
$qb->expr()->eq('deleted', 0),
|
|
$qb->expr()->eq('hidden', 0)
|
|
)
|
|
->executeQuery()
|
|
->fetchAllAssociative();
|
|
|
|
if (empty($ces)) {
|
|
return '';
|
|
}
|
|
|
|
return $this->renderForRecord($ces[0]);
|
|
}
|
|
|
|
/**
|
|
* @param array<string,mixed> $contentElement
|
|
*/
|
|
public function renderForRecord(array $contentElement): string
|
|
{
|
|
try {
|
|
$flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
|
|
$flexFormData = $flexFormService->convertFlexFormContentToArray($contentElement['pi_flexform'] ?? '');
|
|
$settings = $flexFormData['settings'] ?? [];
|
|
|
|
$variant = (string)($settings['variant'] ?? 'grid');
|
|
$mapText = RteResolver::html($settings['maptext'] ?? '');
|
|
$debugMode = (bool)($settings['debug'] ?? false);
|
|
|
|
$qb = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(self::TABLE);
|
|
$rows = $qb
|
|
->select('*')
|
|
->from(self::TABLE)
|
|
->where(
|
|
$qb->expr()->eq('deleted', 0),
|
|
$qb->expr()->eq('hidden', 0)
|
|
)
|
|
->orderBy('sorting', 'ASC')
|
|
->executeQuery()
|
|
->fetchAllAssociative();
|
|
|
|
$locations = array_map(fn(array $r): array => $this->serializeLocation($r), $rows);
|
|
|
|
$response = [
|
|
'variant' => $variant,
|
|
'mapText' => $variant === 'map' && $mapText !== '' ? $mapText : null,
|
|
'locations' => $locations,
|
|
];
|
|
|
|
if ($debugMode) {
|
|
$response['debug'] = ['count' => count($locations), 'settings' => $settings];
|
|
}
|
|
|
|
return (string)json_encode($response);
|
|
} catch (\Throwable $e) {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array<string,mixed> $r
|
|
* @return array<string,mixed>
|
|
*/
|
|
private function serializeLocation(array $r): array
|
|
{
|
|
$name = (string)($r['title'] ?? '');
|
|
|
|
return [
|
|
'id' => (int)$r['uid'],
|
|
'slug' => (string)($r['slug'] ?? ''),
|
|
'name' => $name,
|
|
'countryCode' => (string)($r['country_code'] ?? ''),
|
|
'coordinates' => [
|
|
'latitude' => (float)($r['latitude'] ?? 0),
|
|
'longitude' => (float)($r['longitude'] ?? 0),
|
|
],
|
|
'address' => [
|
|
'company' => $this->nullIfEmpty($r['address_company'] ?? ''),
|
|
'street' => $this->nullIfEmpty($r['street'] ?? ''),
|
|
'additional' => $this->nullIfEmpty($r['address_additional'] ?? ''),
|
|
'postalCode' => $this->nullIfEmpty($r['postal_code'] ?? ''),
|
|
'city' => $this->nullIfEmpty($r['city'] ?? ''),
|
|
'region' => $this->nullIfEmpty($r['region'] ?? ''),
|
|
'country' => $this->nullIfEmpty($r['country'] ?? ''),
|
|
],
|
|
'contact' => [
|
|
'phone' => $this->nullIfEmpty($r['phone'] ?? ''),
|
|
'fax' => $this->nullIfEmpty($r['fax'] ?? ''),
|
|
'email' => $this->nullIfEmpty($r['email'] ?? ''),
|
|
],
|
|
'links' => [
|
|
'contact' => $this->resolveLink((string)($r['contact_link'] ?? '')),
|
|
'legal' => $this->resolveLinkLines((string)($r['legal_links'] ?? '')),
|
|
],
|
|
'marker' => [
|
|
'label' => (string)($r['marker_label'] ?? '') !== '' ? (string)$r['marker_label'] : $name,
|
|
'color' => (string)($r['marker_color'] ?? '#ff6633'),
|
|
'size' => (float)($r['marker_size'] ?? 0.5),
|
|
],
|
|
'sorting' => (int)($r['sorting'] ?? 0),
|
|
'active' => true,
|
|
];
|
|
}
|
|
|
|
private function nullIfEmpty(mixed $value): ?string
|
|
{
|
|
$value = trim((string)$value);
|
|
return $value === '' ? null : $value;
|
|
}
|
|
|
|
/** Resolve a typolink parameter (t3://…, page uid, URL) to a URL/path. */
|
|
private function resolveLink(string $parameter): ?string
|
|
{
|
|
$parameter = trim($parameter);
|
|
if ($parameter === '') {
|
|
return null;
|
|
}
|
|
try {
|
|
$cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
|
|
$url = $cObj->typoLink_URL(['parameter' => $parameter]);
|
|
return $url !== '' ? $url : $parameter;
|
|
} catch (\Throwable $e) {
|
|
return $parameter;
|
|
}
|
|
}
|
|
|
|
/** @return array<int,string> */
|
|
private function resolveLinkLines(string $lines): array
|
|
{
|
|
$out = [];
|
|
foreach (preg_split('/\r\n|\r|\n/', $lines) ?: [] as $line) {
|
|
$resolved = $this->resolveLink($line);
|
|
if ($resolved !== null) {
|
|
$out[] = $resolved;
|
|
}
|
|
}
|
|
return $out;
|
|
}
|
|
}
|