Files
frommeandClaude Opus 5.5 9347112d6b refactor: private instead of protected where nothing relies on it, constructor promotion
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]>
2026-10-26 11:05:45 +01:00

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);
}
}