Markets List and Detail Plugin

This commit is contained in:
2026-08-05 16:53:02 +02:00
parent a739dd8fe3
commit 27cc22dc69
66 changed files with 1078 additions and 5494 deletions

View File

@@ -57,4 +57,18 @@ class MarketController extends ActionController
return $this->htmlResponse();
}
/**
* action list
*
* Extbase registration target for the Marketlist plugin. In headless mode
* the JSON output is produced by MarketListJsonRenderer, not by this
* controller — same arrangement as LocationController::listAction().
*
* @return ResponseInterface
*/
public function listAction(): ResponseInterface
{
return $this->htmlResponse();
}
}

View File

@@ -7,6 +7,7 @@ use Evomedien\Vitec\UserFunc\ProductListJsonRenderer;
use Evomedien\Vitec\UserFunc\ProductShowJsonRenderer;
use Evomedien\Vitec\UserFunc\UsecaseListJsonRenderer;
use Evomedien\Vitec\UserFunc\UsecaseShowJsonRenderer;
use Evomedien\Vitec\UserFunc\MarketListJsonRenderer;
use Evomedien\Vitec\UserFunc\MarketShowJsonRenderer;
use Evomedien\Vitec\UserFunc\SolutionShowJsonRenderer;
use Evomedien\Vitec\UserFunc\DownloadcardJsonRenderer;
@@ -110,6 +111,7 @@ final class ContainerChildrenProcessor implements DataProcessorInterface
'vitec_usecaselist' => [UsecaseListJsonRenderer::class, 'usecases'],
'vitec_usecaseshow' => [UsecaseShowJsonRenderer::class, 'usecase'],
'vitec_marketshow' => [MarketShowJsonRenderer::class, 'market'],
'vitec_marketlist' => [MarketListJsonRenderer::class, 'markets'],
'vitec_solutionshow' => [SolutionShowJsonRenderer::class, 'solution'],
'vitec_downloadcard' => [DownloadcardJsonRenderer::class, 'downloadcard'],
'vitec_downloadcardcollection' => [DownloadcardcollectionJsonRenderer::class, 'downloadcardcollection'],

View File

@@ -13,6 +13,18 @@ class Market extends AbstractEntity
*/
protected $title = '';
/**
* @var string
*/
protected $slug = '';
/**
* Page uid presenting this market (TCA type "group", allowed: pages).
*
* @var int
*/
protected $detailPage = 0;
/**
* @var string
*/
@@ -65,6 +77,38 @@ class Market extends AbstractEntity
$this->title = $title;
}
/**
* @return string
*/
public function getSlug(): string
{
return $this->slug;
}
/**
* @param string $slug
*/
public function setSlug(string $slug): void
{
$this->slug = $slug;
}
/**
* @return int
*/
public function getDetailPage(): int
{
return $this->detailPage;
}
/**
* @param int $detailPage
*/
public function setDetailPage(int $detailPage): void
{
$this->detailPage = $detailPage;
}
/**
* @return string
*/

View File

@@ -13,6 +13,11 @@ class Solution extends AbstractEntity
*/
protected $title = '';
/**
* @var string
*/
protected $slug = '';
/**
* @var string
*/
@@ -65,6 +70,22 @@ class Solution extends AbstractEntity
$this->title = $title;
}
/**
* @return string
*/
public function getSlug(): string
{
return $this->slug;
}
/**
* @param string $slug
*/
public function setSlug(string $slug): void
{
$this->slug = $slug;
}
/**
* @return string
*/

View File

@@ -9,6 +9,7 @@ use Evomedien\Vitec\UserFunc\ProductListJsonRenderer;
use Evomedien\Vitec\UserFunc\ProductShowJsonRenderer;
use Evomedien\Vitec\UserFunc\UsecaseListJsonRenderer;
use Evomedien\Vitec\UserFunc\UsecaseShowJsonRenderer;
use Evomedien\Vitec\UserFunc\MarketListJsonRenderer;
use Evomedien\Vitec\UserFunc\MarketShowJsonRenderer;
use Evomedien\Vitec\UserFunc\SolutionShowJsonRenderer;
use Evomedien\Vitec\UserFunc\DownloadcardJsonRenderer;
@@ -75,6 +76,7 @@ final class ContentElementResolver
'vitec_usecaselist' => [UsecaseListJsonRenderer::class, 'usecases'],
'vitec_usecaseshow' => [UsecaseShowJsonRenderer::class, 'usecase'],
'vitec_marketshow' => [MarketShowJsonRenderer::class, 'market'],
'vitec_marketlist' => [MarketListJsonRenderer::class, 'markets'],
'vitec_solutionshow' => [SolutionShowJsonRenderer::class, 'solution'],
'vitec_downloadcard' => [DownloadcardJsonRenderer::class, 'downloadcard'],
'vitec_downloadcardcollection' => [DownloadcardcollectionJsonRenderer::class, 'downloadcardcollection'],

View File

@@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace Evomedien\Vitec\Service;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
/**
* Turns raw richtext (RTE) database content into frontend-ready HTML.
*
* TYPO3 stores RTE fields with unresolved internal references: internal links as
* `<a href="t3://page?uid=12">`, legacy content as `<link>` tags, images with
* relative paths. Fluid resolves those through `parseFunc` when it renders; a
* headless UserFunc renderer that hands the raw column straight to JSON does
* not, and the frontend receives dead links.
*
* The two upstream packages already close this gap for the output they own:
* `friendsoftypo3/headless` applies `parseFunc =< lib.parseFunc_RTE` to the core
* text elements via TypoScript, and `nb-headless-content-blocks` calls
* `parseFunc($value, null, '< lib.parseFunc_RTE')` for every Content Block field
* whose TCA has `enableRichtext`. This class closes it for the VITEC UserFunc
* renderers, using exactly the same call.
*
* Static by design: the conversion is stateless, and the call sites are payload
* array literals where a `GeneralUtility::makeInstance(...)->` prefix would add
* only noise. Same rationale as `CropVariants::firstImage()` and
* `FormDefinitions::get()`.
*
* Fail-soft per architecture spec clause 9.5: when parsing is impossible — most
* notably outside a frontend request, where no TypoScript setup exists — the raw
* value is returned. Content is never lost; at worst it stays unresolved.
*/
final class RteResolver
{
/**
* @param mixed $value raw column value; null and non-strings are tolerated
*/
public static function html(mixed $value): string
{
$raw = (string)($value ?? '');
if (trim($raw) === '') {
return '';
}
try {
$parsed = GeneralUtility::makeInstance(ContentObjectRenderer::class)
->parseFunc($raw, null, '< lib.parseFunc_RTE');
return $parsed !== '' ? $parsed : $raw;
} catch (\Throwable $e) {
return $raw;
}
}
}

View File

@@ -11,6 +11,7 @@ use TYPO3\CMS\Core\Core\Environment;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Service\FlexFormService;
use Evomedien\Vitec\Service\RteResolver;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Service\ImageService;
@@ -261,7 +262,7 @@ class DatasheetsJsonRenderer
'title' => (string)($download['title'] ?? ''),
'slug' => (string)($download['slug'] ?? ''),
'teaser' => (string)($download['teaser'] ?? ''),
'description' => (string)($download['description'] ?? ''),
'description' => RteResolver::html($download['description'] ?? ''),
'tstamp' => (int)($download['tstamp'] ?? 0),
'filetype' => $filetype,
'file' => $this->getDownloadFile($uid, (string)($download['fileprefix'] ?? ''), $filetype),

View File

@@ -10,6 +10,7 @@ use Doctrine\DBAL\ParameterType;
use TYPO3\CMS\Core\Core\Environment;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Service\FlexFormService;
use Evomedien\Vitec\Service\RteResolver;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
@@ -254,7 +255,7 @@ class DownloadcardJsonRenderer
'title' => (string)($download['title'] ?? ''),
'slug' => (string)($download['slug'] ?? ''),
'teaser' => (string)($download['teaser'] ?? ''),
'description' => (string)($download['description'] ?? ''),
'description' => RteResolver::html($download['description'] ?? ''),
'keywords' => (string)($download['keywords'] ?? ''),
'icon' => (string)($download['icon'] ?? ''),
'filepath' => (string)($download['filepath'] ?? ''),

View File

@@ -12,6 +12,7 @@ use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Service\FlexFormService;
use Evomedien\Vitec\Service\RteResolver;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Service\ImageService;
@@ -258,7 +259,7 @@ class DownloadcardcollectionJsonRenderer
'title' => (string)($download['title'] ?? ''),
'slug' => (string)($download['slug'] ?? ''),
'teaser' => (string)($download['teaser'] ?? ''),
'description' => (string)($download['description'] ?? ''),
'description' => RteResolver::html($download['description'] ?? ''),
'keywords' => (string)($download['keywords'] ?? ''),
'icon' => (string)($download['icon'] ?? ''),
'filepath' => (string)($download['filepath'] ?? ''),

View File

@@ -9,6 +9,7 @@ use TYPO3\CMS\Core\Attribute\AsAllowedCallable;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Service\FlexFormService;
use Evomedien\Vitec\Service\RteResolver;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Service\ImageService;
@@ -195,7 +196,7 @@ class EventlistJsonRenderer
'title' => (string)($event['title'] ?? ''),
'slug' => (string)($event['slug'] ?? ''),
'teaser' => (string)($event['teaser'] ?? ''),
'description' => (string)($event['description'] ?? ''),
'description' => RteResolver::html($event['description'] ?? ''),
'eventstart' => $start > 0 ? date('Y-m-d', $start) : null,
'eventend' => $end > 0 ? date('Y-m-d', $end) : null,
'venue' => (string)($event['venue'] ?? ''),

View File

@@ -8,6 +8,7 @@ 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;
@@ -82,7 +83,7 @@ class LocationsJsonRenderer
$settings = $flexFormData['settings'] ?? [];
$variant = (string)($settings['variant'] ?? 'grid');
$mapText = trim((string)($settings['maptext'] ?? ''));
$mapText = RteResolver::html($settings['maptext'] ?? '');
$debugMode = (bool)($settings['debug'] ?? false);
$qb = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(self::TABLE);

View File

@@ -0,0 +1,196 @@
<?php
declare(strict_types=1);
namespace Evomedien\Vitec\UserFunc;
use Doctrine\DBAL\ParameterType;
use Evomedien\Vitec\Service\RteResolver;
use Evomedien\Vitec\Service\UsecaseSerializer;
use TYPO3\CMS\Core\Attribute\AsAllowedCallable;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Service\FlexFormService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
/**
* UserFunc: render all VITEC markets as JSON (headless).
*
* Output under content.markets:
* { "layout": "grid|list|carousel", "markets": [ … ] }
*
* Selection semantics (FlexForm `settings.markets`):
* - nothing selected -> ALL visible markets, alphabetical by title
* (tx_vitec_domain_model_market has no `sorting` column)
* - markets selected -> exactly those, in the order the editor arranged
* them in the FlexForm
*
* The page carrying the plugin is never used as a filter.
*
* Each item uses the same shape as the card payload (ModelcardJsonRenderer,
* model type "market"), so the frontend can render list and single card with
* one component. Image resolution is delegated to UsecaseSerializer::image()
* rather than re-implemented inline (architecture spec, clause 9.2).
*
* `render()` = top-level plugin / page discovery. `renderForRecord()` = one
* specific tt_content row (reused by ContainerChildrenProcessor for nested
* plugins). Exception-safe.
*/
class MarketListJsonRenderer
{
private const TABLE = 'tx_vitec_domain_model_market';
private const CTYPE = 'vitec_marketlist';
#[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'] ?? '') === self::CTYPE) {
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(self::CTYPE, 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'] ?? [];
$layout = (string)($settings['layout'] ?? 'grid');
$debugMode = (bool)($settings['debug'] ?? false);
$selectedUids = GeneralUtility::intExplode(',', (string)($settings['markets'] ?? ''), true);
// Always fetch the full (small) table once — that way a selected
// record that has meanwhile been hidden or deleted simply drops out.
$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('title', 'ASC')
->executeQuery()
->fetchAllAssociative();
$serializer = GeneralUtility::makeInstance(UsecaseSerializer::class);
if ($selectedUids === []) {
$markets = array_map(
fn(array $r): array => $this->serializeMarket($r, $serializer),
$rows
);
} else {
// Keep the editor's FlexForm order. A SQL IN() would return the
// rows in storage order, so the sequence is rebuilt here.
$byUid = [];
foreach ($rows as $r) {
$byUid[(int)$r['uid']] = $r;
}
$markets = [];
foreach ($selectedUids as $uid) {
if (isset($byUid[$uid])) {
$markets[] = $this->serializeMarket($byUid[$uid], $serializer);
}
}
}
$response = [
'layout' => $layout,
'markets' => $markets,
];
if ($debugMode) {
$response['debug'] = [
'count' => count($markets),
'selected' => $selectedUids,
'settings' => $settings,
];
}
return (string)json_encode($response);
} catch (\Throwable $e) {
return '';
}
}
/**
* @param array<string,mixed> $r
* @return array<string,mixed>
*/
private function serializeMarket(array $r, UsecaseSerializer $serializer): array
{
$uid = (int)$r['uid'];
return [
'uid' => $uid,
'title' => (string)($r['title'] ?? ''),
'slug' => (string)($r['slug'] ?? ''),
'subtitle' => (string)($r['subtitle'] ?? ''),
'teaser' => (string)($r['teaser'] ?? ''),
'description' => RteResolver::html($r['description'] ?? ''),
'detailUrl' => $this->detailUrl((int)($r['detail_page'] ?? 0)),
'image' => $serializer->image($uid, 'image', self::TABLE, true),
];
}
/**
* Resolve the `detail_page` uid to a URL. The frontend cannot do anything
* with a raw page uid, so the link is built server side — same convention
* as `headerLink` and LocationsJsonRenderer.
*
* Returns null when no page is set or the link cannot be resolved.
*/
private function detailUrl(int $pageUid): ?string
{
if ($pageUid <= 0) {
return null;
}
try {
$cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
$url = $cObj->typoLink_URL(['parameter' => (string)$pageUid]);
return $url !== '' ? $url : null;
} catch (\Throwable $e) {
return null;
}
}
}

View File

@@ -10,8 +10,10 @@ use Doctrine\DBAL\ParameterType;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Service\FlexFormService;
use Evomedien\Vitec\Service\RteResolver;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Service\ImageService;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
/**
* UserFunc to render a single market as JSON for headless output.
@@ -155,9 +157,11 @@ class MarketShowJsonRenderer
return [
'uid' => $uid,
'title' => (string)($market['title'] ?? ''),
'slug' => (string)($market['slug'] ?? ''),
'subtitle' => (string)($market['subtitle'] ?? ''),
'teaser' => (string)($market['teaser'] ?? ''),
'description' => (string)($market['description'] ?? ''),
'description' => RteResolver::html($market['description'] ?? ''),
'detailUrl' => $this->detailUrl((int)($market['detail_page'] ?? 0)),
'categories' => $this->getMarketCategories($uid),
'image' => $this->getMarketImage($uid),
];
@@ -267,4 +271,25 @@ class MarketShowJsonRenderer
];
}, $categories);
}
/**
* Resolve the `detail_page` uid to a URL. The frontend cannot do anything
* with a raw page uid, so the link is built server side — same convention
* as `headerLink` and LocationsJsonRenderer.
*
* Returns null when no page is set or the link cannot be resolved.
*/
private function detailUrl(int $pageUid): ?string
{
if ($pageUid <= 0) {
return null;
}
try {
$cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
$url = $cObj->typoLink_URL(['parameter' => (string)$pageUid]);
return $url !== '' ? $url : null;
} catch (\Throwable $e) {
return null;
}
}
}

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Evomedien\Vitec\UserFunc;
use Doctrine\DBAL\ParameterType;
use Evomedien\Vitec\Service\RteResolver;
use Evomedien\Vitec\Service\UsecaseSerializer;
use TYPO3\CMS\Core\Attribute\AsAllowedCallable;
use TYPO3\CMS\Core\Database\ConnectionPool;
@@ -166,9 +167,10 @@ class ModelcardJsonRenderer
return [
'uid' => $uid,
'title' => (string)($row['title'] ?? ''),
'slug' => (string)($row['slug'] ?? ''),
'subtitle' => (string)($row['subtitle'] ?? ''),
'teaser' => (string)($row['teaser'] ?? ''),
'description' => (string)($row['description'] ?? ''),
'description' => RteResolver::html($row['description'] ?? ''),
'image' => $serializer->image($uid, 'image', self::MODEL_TABLES[$modelType], true),
];
}

View File

@@ -11,6 +11,7 @@ use TYPO3\CMS\Core\Attribute\AsAllowedCallable;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Service\FlexFormService;
use Evomedien\Vitec\Service\RteResolver;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Service\ImageService;
@@ -319,7 +320,7 @@ final class NewsJsonRenderer
'detailUrl' => $urls['detailUrl'],
'canonicalUrl' => $urls['canonicalUrl'],
'teaser' => (string)($news['teaser'] ?? ''),
'bodytext' => (string)($news['bodytext'] ?? ''),
'bodytext' => RteResolver::html($news['bodytext'] ?? ''),
'datetime' => (int)($news['datetime'] ?? 0),
'archive' => (int)($news['archive'] ?? 0),
'istopnews' => (bool)($news['istopnews'] ?? false),

View File

@@ -16,6 +16,7 @@ use TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection;
use TYPO3\CMS\Core\Resource\FileReference;
use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Service\FlexFormService;
use Evomedien\Vitec\Service\RteResolver;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Service\ImageService;
@@ -177,9 +178,9 @@ class ProductListJsonRenderer
'teaser' => (string)($product['teaser'] ?? ''),
'subtitle' => (string)($product['subtitle'] ?? ''),
'video' => (string)($product['video'] ?? ''),
'applications' => (string)($product['applications'] ?? ''),
'description' => (string)($product['description'] ?? ''),
'highlights' => (string)($product['highlights'] ?? ''),
'applications' => RteResolver::html($product['applications'] ?? ''),
'description' => RteResolver::html($product['description'] ?? ''),
'highlights' => RteResolver::html($product['highlights'] ?? ''),
'shortcutpid' => (string)($product['shortcutpid'] ?? ''),
'contentelement' => \Evomedien\Vitec\Service\ContentElementResolver::resolveLink((string)($product['contentelement'] ?? '')),
'contentelementcta' => \Evomedien\Vitec\Service\ContentElementResolver::resolveLink((string)($product['contentelementcta'] ?? '')),
@@ -697,7 +698,7 @@ class ProductListJsonRenderer
'title' => $download['title'] ?? '',
'slug' => $download['slug'] ?? '',
'teaser' => $download['teaser'] ?? '',
'description' => $download['description'] ?? '',
'description' => RteResolver::html($download['description'] ?? ''),
'keywords' => $download['keywords'] ?? '',
'icon' => $download['icon'] ?? '',
'fileprefix' => $fileprefix,
@@ -741,7 +742,7 @@ class ProductListJsonRenderer
'slug' => (string)($rel['slug'] ?? ''),
'subtitle' => (string)($rel['subtitle'] ?? ''),
'teaser' => (string)($rel['teaser'] ?? ''),
'description' => (string)($rel['description'] ?? ''),
'description' => RteResolver::html($rel['description'] ?? ''),
'link' => '/product/' . (string)($rel['slug'] ?? ''),
'images' => $this->getProductImages($relUid),
];

View File

@@ -10,6 +10,7 @@ use TYPO3\CMS\Core\Attribute\AsAllowedCallable;
use TYPO3\CMS\Core\Core\Environment;
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\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection;
@@ -192,9 +193,9 @@ class ProductShowJsonRenderer
'teaser' => (string)($product['teaser'] ?? ''),
'subtitle' => (string)($product['subtitle'] ?? ''),
'video' => (string)($product['video'] ?? ''),
'applications' => (string)($product['applications'] ?? ''),
'description' => (string)($product['description'] ?? ''),
'highlights' => (string)($product['highlights'] ?? ''),
'applications' => RteResolver::html($product['applications'] ?? ''),
'description' => RteResolver::html($product['description'] ?? ''),
'highlights' => RteResolver::html($product['highlights'] ?? ''),
'shortcutpid' => (string)($product['shortcutpid'] ?? ''),
'contentelement' => \Evomedien\Vitec\Service\ContentElementResolver::resolveLink((string)($product['contentelement'] ?? '')),
'contentelementcta' => \Evomedien\Vitec\Service\ContentElementResolver::resolveLink((string)($product['contentelementcta'] ?? '')),
@@ -769,7 +770,7 @@ class ProductShowJsonRenderer
'title' => $download['title'] ?? '',
'slug' => $download['slug'] ?? '',
'teaser' => $download['teaser'] ?? '',
'description' => $download['description'] ?? '',
'description' => RteResolver::html($download['description'] ?? ''),
'keywords' => $download['keywords'] ?? '',
'icon' => $download['icon'] ?? '',
'fileprefix' => $fileprefix,
@@ -813,7 +814,7 @@ class ProductShowJsonRenderer
'slug' => (string)($rel['slug'] ?? ''),
'subtitle' => (string)($rel['subtitle'] ?? ''),
'teaser' => (string)($rel['teaser'] ?? ''),
'description' => (string)($rel['description'] ?? ''),
'description' => RteResolver::html($rel['description'] ?? ''),
'link' => '/product/' . (string)($rel['slug'] ?? ''),
'images' => $this->getProductImages($relUid),
];

View File

@@ -10,6 +10,7 @@ use Doctrine\DBAL\ParameterType;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Service\FlexFormService;
use Evomedien\Vitec\Service\RteResolver;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Service\ImageService;
@@ -155,9 +156,10 @@ class SolutionShowJsonRenderer
return [
'uid' => $uid,
'title' => (string)($solution['title'] ?? ''),
'slug' => (string)($solution['slug'] ?? ''),
'subtitle' => (string)($solution['subtitle'] ?? ''),
'teaser' => (string)($solution['teaser'] ?? ''),
'description' => (string)($solution['description'] ?? ''),
'description' => RteResolver::html($solution['description'] ?? ''),
'categories' => $this->getSolutionCategories($uid),
'image' => $this->getSolutionImage($uid),
];