Files
VITEC-website/packages/vitec/Classes/Preview/ModelcardPreviewRenderer.php
khaccount eae40f4286 Success-story migration + new plugins + JSON/UX polish
- Success Stories: full migration from old site (48/48, audited),
  markets n:n, quotation content block, columns content block,
  pretty SEO detail URLs via SuccessStoryPathRewrite middleware,
  list/detail split (list page 4 / story page), detailUrl/backUrl
- New plugins: VITEC Locations (grid/list/map + RTE map text),
  VITEC Customer Logos (color/bw logic, only-show-selected),
  VITEC Card (one plugin for product/story/market/solution
  with reloading FlexForm + custom backend preview renderer)
- Eventlist: layout dropdown (list/grid/teaserbar) in settings
- Hero section CB: Images/Video tabs, background video + overlay
- Product JSON: full category rootline (parents), fixed missing
  ConnectionPool import (all-products crash), category tree map
- Backend preview CSS: container-query responsive (narrow columns)
- Docs: ISO architecture spec, root + extension READMEs

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 09:53:33 +02:00

128 lines
5.0 KiB
PHP
Executable File

<?php
declare(strict_types=1);
namespace Evomedien\Vitec\Preview;
use Doctrine\DBAL\ParameterType;
use TYPO3\CMS\Backend\Preview\StandardContentPreviewRenderer;
use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridColumnItem;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Service\FlexFormService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Fluid\View\StandaloneView;
/**
* Page-module preview for the VITEC Card plugin (vitec_modelcard):
* type badge, selected record title, thumbnail and layout badge.
* Registered via TCA types.vitec_modelcard.previewRenderer.
*/
class ModelcardPreviewRenderer extends StandardContentPreviewRenderer
{
private const MODEL_TABLES = [
'product' => 'tx_vitec_domain_model_product',
'story' => 'tx_vitec_domain_model_usecase',
'market' => 'tx_vitec_domain_model_market',
'solution' => 'tx_vitec_domain_model_solution',
];
private const TYPE_LABELS = [
'product' => 'Product',
'story' => 'Success Story',
'market' => 'Market',
'solution' => 'Solution',
];
/** Card-image FAL field per model type (first hit wins). */
private const IMAGE_FIELDS = [
'product' => ['image', 'productimage'],
'story' => ['card_image', 'hero_bgimage'],
'market' => ['image'],
'solution' => ['image'],
];
public function renderPageModulePreviewContent(GridColumnItem $item): string
{
try {
$record = $item->getRecord();
$flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
$flexFormData = $flexFormService->convertFlexFormContentToArray($record['pi_flexform'] ?? '');
$settings = $flexFormData['settings'] ?? [];
$modelType = (string)($settings['modelType'] ?? 'product');
$layout = (string)($settings['layout'] ?? 'vertical');
$recordUid = (int)($settings[$modelType === 'story' ? 'story' : $modelType] ?? 0);
$title = '';
$subtitle = '';
$imageUrl = '';
if ($recordUid > 0 && isset(self::MODEL_TABLES[$modelType])) {
$table = self::MODEL_TABLES[$modelType];
$qb = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
$row = $qb
->select('*')
->from($table)
->where(
$qb->expr()->eq('uid', $qb->createNamedParameter($recordUid, ParameterType::INTEGER)),
$qb->expr()->eq('deleted', 0)
)
->executeQuery()
->fetchAssociative();
if ($row) {
$title = (string)($row['title'] ?? '');
$subtitle = (string)($row['subtitle'] ?? ($row['teaser'] ?? ''));
$imageUrl = $this->firstImageUrl($table, $recordUid, self::IMAGE_FIELDS[$modelType]);
}
}
$view = GeneralUtility::makeInstance(StandaloneView::class);
$view->setTemplatePathAndFilename('EXT:vitec/Resources/Private/Templates/Preview/Modelcard.html');
$view->assignMultiple([
'typeLabel' => self::TYPE_LABELS[$modelType] ?? $modelType,
'layout' => $layout,
'recordUid' => $recordUid,
'title' => $title,
'subtitle' => $subtitle,
'imageUrl' => $imageUrl,
]);
return $view->render();
} catch (\Throwable $e) {
return parent::renderPageModulePreviewContent($item);
}
}
/** @param string[] $fieldNames */
private function firstImageUrl(string $table, int $uid, array $fieldNames): string
{
try {
$qb = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_file_reference');
foreach ($fieldNames as $fieldName) {
$ref = $qb
->select('uid')
->from('sys_file_reference')
->where(
$qb->expr()->eq('tablenames', $qb->createNamedParameter($table, ParameterType::STRING)),
$qb->expr()->eq('fieldname', $qb->createNamedParameter($fieldName, ParameterType::STRING)),
$qb->expr()->eq('uid_foreign', $qb->createNamedParameter($uid, ParameterType::INTEGER)),
$qb->expr()->eq('deleted', 0),
$qb->expr()->eq('hidden', 0)
)
->setMaxResults(1)
->executeQuery()
->fetchAssociative();
if ($ref) {
$file = GeneralUtility::makeInstance(ResourceFactory::class)
->getFileReferenceObject((int)$ref['uid']);
return (string)$file->getPublicUrl();
}
}
} catch (\Throwable $e) {
// no thumb
}
return '';
}
}