Members (properties, methods, constants) become private when they are declared in the class itself, no parent class or interface declares them, no ancestor in packages/ uses them and the class has no subclass in packages/: 115 members in 36 files. Extbase domain objects keep protected properties, AbstractDomainObject sets them from the parent class. With the properties private, Rector's constructor promotion now also applies to the controllers and services that still assigned their dependencies by hand (26 files). Checked locally: frontend crawl (~1,900 URLs) and the backchannel APIs render the same as before. Co-Authored-By: Claude Opus 5.5 <[email protected]>
121 lines
5.8 KiB
PHP
121 lines
5.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace EP\EpTheme\Preview;
|
|
|
|
use TYPO3\CMS\Backend\Preview\StandardContentPreviewRenderer;
|
|
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
|
use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridColumnItem;
|
|
use TYPO3\CMS\Core\Database\ConnectionPool;
|
|
use TYPO3\CMS\Core\Resource\FileRepository;
|
|
use TYPO3\CMS\Core\Service\FlexFormService;
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
|
use TYPO3\CMS\Core\View\ViewFactoryData;
|
|
use TYPO3\CMS\Core\View\ViewFactoryInterface;
|
|
|
|
/**
|
|
* Page module previews of the theme's content elements, rendered from
|
|
* Templates/PreviewRenderer/<CType>.html as the TYPO3 10 drawItem hooks did
|
|
* (Classes/Hooks/PageLayoutView in a46918d), with the same template variables.
|
|
* Registered per CType in TCA (['types'][<CType>]['previewRenderer']).
|
|
*/
|
|
class ContentPreviewRenderer extends StandardContentPreviewRenderer
|
|
{
|
|
/**
|
|
* CType => [field holding the related uid, related table, template variable]
|
|
*/
|
|
private const array RELATED_RECORDS = [
|
|
'teaser_country' => ['tx_eptheme_context_country', 'tx_epproducts_domain_model_country', 'country'],
|
|
'teaser_region' => ['tx_eptheme_context_region', 'tx_epproducts_domain_model_region', 'region'],
|
|
'teaser_city' => ['tx_eptheme_context_city', 'tx_epproducts_domain_model_city', 'city'],
|
|
'teaser_hotel' => ['tx_eptheme_context_hotel', 'tx_epproducts_domain_model_hotel', 'hotel'],
|
|
'teaser_concept' => ['tx_eptheme_context_concept', 'tx_epproducts_domain_model_concept', 'concept'],
|
|
'teaser_product' => ['tx_eptheme_context_product', 'tx_epproducts_domain_model_product', 'product'],
|
|
'teaser_booking_link' => ['tx_eptheme_context_product', 'tx_epproducts_domain_model_product', 'product'],
|
|
];
|
|
|
|
public function renderPageModulePreviewContent(GridColumnItem $item): string
|
|
{
|
|
$row = $item->getRecord();
|
|
$cType = (string)$row['CType'];
|
|
$template = GeneralUtility::getFileAbsFileName(
|
|
'EXT:ep_theme/Resources/Private/Templates/PreviewRenderer/' . GeneralUtility::underscoredToUpperCamelCase($cType) . '.html'
|
|
);
|
|
if (!is_file($template)) {
|
|
return parent::renderPageModulePreviewContent($item);
|
|
}
|
|
|
|
$images = $this->getImages((int)$row['uid'], 'tt_content', 'image');
|
|
$variables = [
|
|
'data' => $row,
|
|
'flexForm' => GeneralUtility::makeInstance(FlexFormService::class)->convertFlexFormContentToArray((string)($row['pi_flexform'] ?? '')),
|
|
'firstImage' => $images[0] ?? null,
|
|
'images' => $images,
|
|
];
|
|
$variables = array_replace($variables, $this->getAssignmentsForTemplate($cType, $row));
|
|
|
|
$view = GeneralUtility::makeInstance(ViewFactoryInterface::class)->create(new ViewFactoryData(
|
|
templatePathAndFilename: $template,
|
|
request: $item->getContext()->getCurrentRequest(),
|
|
));
|
|
$view->assignMultiple($variables);
|
|
return $view->render();
|
|
}
|
|
|
|
private function getAssignmentsForTemplate(string $cType, array $row): array
|
|
{
|
|
if (isset(self::RELATED_RECORDS[$cType])) {
|
|
[$field, $table, $name] = self::RELATED_RECORDS[$cType];
|
|
$uid = (int)($row[$field] ?? 0);
|
|
$assignments = [
|
|
'images' => $this->getImages($uid, $table, 'teaser_images'),
|
|
$name => $uid > 0 ? BackendUtility::getRecord($table, $uid) : null,
|
|
];
|
|
if ($cType === 'teaser_product') {
|
|
$hotelUid = (int)($row['tx_eptheme_context_hotel'] ?? 0);
|
|
$assignments['hotel'] = $hotelUid > 0 ? BackendUtility::getRecord('tx_epproducts_domain_model_hotel', $hotelUid) : null;
|
|
}
|
|
return $assignments;
|
|
}
|
|
|
|
switch ($cType) {
|
|
case 'gmap':
|
|
$regionUid = (int)($row['tx_eptheme_context_region'] ?? 0);
|
|
$content = $regionUid > 0
|
|
? BackendUtility::getRecord('tx_epproducts_domain_model_region', $regionUid)
|
|
: BackendUtility::getRecord('tx_epproducts_domain_model_hotel', (int)($row['tx_eptheme_context_hotel'] ?? 0));
|
|
return ['content' => $content];
|
|
case 'disrupter':
|
|
// tx_eptheme_disrupter is an MM relation; the field itself only holds the count
|
|
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_eptheme_ttcontent_tx_eptheme_disrupter_mm');
|
|
$disrupterUid = (int)$queryBuilder->select('uid_foreign')
|
|
->from('tx_eptheme_ttcontent_tx_eptheme_disrupter_mm')
|
|
->where($queryBuilder->expr()->eq('uid_local', $queryBuilder->createNamedParameter((int)$row['uid'])))
|
|
->orderBy('sorting')
|
|
->setMaxResults(1)
|
|
->executeQuery()
|
|
->fetchOne();
|
|
return ['content' => $disrupterUid > 0 ? BackendUtility::getRecord('tx_eptheme_domain_model_disrupter', $disrupterUid) : null];
|
|
case 'lineup':
|
|
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_eptheme_domain_model_lineup');
|
|
$rows = $queryBuilder->select('*')
|
|
->from('tx_eptheme_domain_model_lineup')
|
|
->where($queryBuilder->expr()->eq('tt_content', $queryBuilder->createNamedParameter((int)$row['uid'])))
|
|
->orderBy('sorting')
|
|
->executeQuery()
|
|
->fetchAllAssociative();
|
|
return ['rows' => $rows];
|
|
}
|
|
return [];
|
|
}
|
|
|
|
private function getImages(int $uid, string $table, string $field): array
|
|
{
|
|
if ($uid <= 0) {
|
|
return [];
|
|
}
|
|
return GeneralUtility::makeInstance(FileRepository::class)->findByRelation($table, $field, $uid);
|
|
}
|
|
}
|