ready to be rendered.
*/
#[Autoconfigure(public: true)]
final readonly class RecordFieldPreviewProcessor
{
public function __construct(
private TcaSchemaFactory $schemaFactory,
private UriBuilder $uriBuilder,
private IconFactory $iconFactory,
private SanitizerBuilderFactory $sanitizerBuilderFactory,
#[Autowire(service: 'cache.runtime')]
private FrontendInterface $runtimeCache,
) {}
/**
* Prepare the value of a field but prepend the label before.
*/
public function prepareFieldWithLabel(RecordInterface $record, string $fieldName): ?string
{
if ($record->has($fieldName)) {
$table = $record->getMainType();
$value = $record->get($fieldName);
if ($value !== '' && $value !== null) {
$itemLabels = $this->getItemLabels($record);
$fieldValue = BackendUtility::getProcessedValue($table, $fieldName, $value, 0, false, false, $record->getUid(), true, $record->getPid(), $record->getRawRecord()->toArray()) ?? '';
if ($fieldValue !== '') {
return htmlspecialchars((string)($itemLabels[$fieldName] ?? '')) . ': ' . htmlspecialchars((string)$fieldValue);
}
}
}
return null;
}
/**
* Prepare the value of a field if it exists and it is not empty.
*/
public function prepareField(RecordInterface $record, string $fieldName): ?string
{
if ($record->has($fieldName)) {
$table = $record->getMainType();
$value = $record->get($fieldName);
if ($value !== '' && $value !== null) {
$fieldValue = BackendUtility::getProcessedValue($table, $fieldName, $value, 0, false, false, $record->getUid(), true, $record->getPid(), $record->getRawRecord()->toArray()) ?? '';
if ($fieldValue !== '') {
return htmlspecialchars((string)$fieldValue);
}
}
}
return null;
}
/**
* Processing of larger amounts of text (usually from RTE/bodytext fields) with word wrapping, etc.
*/
public function prepareText(RecordInterface $record, string $fieldName, int $maxLength = 1500): ?string
{
if ($record->has($fieldName)) {
$input = $record->get($fieldName);
$schemaForType = $this->schemaFactory->get($record->getFullType());
if (is_string($input) && $input !== '' && $schemaForType->hasField($fieldName)) {
$isSimpleText = $schemaForType->getField($fieldName)->isType(TableColumnType::INPUT);
if (!$isSimpleText) {
$input = strip_tags($input);
}
$input = GeneralUtility::fixed_lgd_cs($input, $maxLength);
return nl2br(htmlspecialchars(trim($input), ENT_QUOTES, 'UTF-8', false));
}
}
return null;
}
public function preparePlainHtml(RecordInterface $record, string $fieldName, int $maxLines = 100): ?string
{
if ($record->has($fieldName)) {
$html = GeneralUtility::trimExplode(LF, (string)$record->get($fieldName), true);
if ($html !== []) {
$html = array_slice($html, 0, $maxLines);
return str_replace(LF, '
', htmlspecialchars(implode(LF, $html)));
}
}
return null;
}
public function preparePreviewableHtml(RecordInterface $record, string $fieldName): ?string
{
if ($record->has($fieldName)) {
$content = $record->get($fieldName);
if (!is_string($content)) {
return null;
}
$builder = $this->sanitizerBuilderFactory->build('preview');
return $builder->build()->sanitize($content);
}
return null;
}
/**
* Render thumbnails for a file collection or files.
*/
public function prepareFiles(iterable|FileReference $fileReferences): ?string
{
$thumbData = [];
$fileReferences = $fileReferences instanceof FileReference ? [$fileReferences] : $fileReferences;
foreach ($fileReferences as $fileReferenceObject) {
// Do not show previews of hidden references
if ($fileReferenceObject->getProperty('hidden')) {
continue;
}
$fileObject = $fileReferenceObject->getOriginalFile();
if ($fileObject->isMissing()) {
$thumbData[] = $this->iconFactory
->getIcon('mimetypes-other-other', IconSize::MEDIUM, 'overlay-missing')
->setTitle($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:warning.file_missing') . ' ' . $fileObject->getName())
->render();
continue;
}
// Preview web image or media elements
if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['thumbnails']
&& ($fileReferenceObject->getOriginalFile()->isImage() || $fileReferenceObject->getOriginalFile()->isMediaFile())
) {
$cropVariantCollection = CropVariantCollection::create((string)$fileReferenceObject->getProperty('crop'));
$cropArea = $cropVariantCollection->getCropArea();
$processingConfiguration = [
'maxWidth' => 64,
'maxHeight' => 64,
];
if (!$cropArea->isEmpty()) {
$processingConfiguration = [
'maxWidth' => 64,
'maxHeight' => 64,
'crop' => $cropArea->makeAbsoluteBasedOnFile($fileReferenceObject),
];
}
$processedImage = $fileObject->process(ProcessedFile::CONTEXT_IMAGECROPSCALEMASK, $processingConfiguration);
$attributes = [
'src' => $processedImage->getPublicUrl() ?? '',
'width' => $processedImage->getProperty('width'),
'height' => $processedImage->getProperty('height'),
'alt' => $fileReferenceObject->getAlternative() ?: $fileReferenceObject->getName(),
'loading' => 'lazy',
];
$thumbData[] = '';
} else {
$thumbData[] = $this->iconFactory->getIconForResource($fileObject)->setTitle($fileObject->getName())->render();
}
}
if ($thumbData !== []) {
$result = '';
foreach ($thumbData as $thumbDataItem) {
$result .= '