Formular-Infrastruktur: Contact/Demo/Helpdesk mit E-Mail- und Salesforce-Delivery, JSON-Renderer-Erweiterungen, Crop-Variants
Build-Artefakte in public/_frontend/assets nicht enthalten.
This commit is contained in:
1 parent
eae40f4286
commit
a739dd8fe3
51 files changed
+1598
-303
No files matched your search
@@ -9,6 +9,7 @@ use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Service\ImageService;
|
||||
use TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection;
|
||||
|
||||
/**
|
||||
* Serialises a Success Story (tx_vitec_domain_model_usecase) DB row to the
|
||||
@@ -43,7 +44,7 @@ final class UsecaseSerializer
|
||||
'slug' => (string)($u['slug'] ?? ''),
|
||||
'subtitle' => (string)($u['subtitle'] ?? ''),
|
||||
'teaser' => (string)($u['teaser'] ?? ''),
|
||||
'cardImage' => $this->image($uid, 'card_image'),
|
||||
'cardImage' => $this->image($uid, 'card_image', null, true),
|
||||
'customerLogo' => $this->image($uid, 'customer_logo'),
|
||||
'markets' => $this->relationMulti('tx_vitec_usecase_market_mm', 'tx_vitec_domain_model_market', $uid),
|
||||
'categories' => $this->categories($uid),
|
||||
@@ -100,7 +101,7 @@ final class UsecaseSerializer
|
||||
*
|
||||
* @return array<string,mixed>|null
|
||||
*/
|
||||
public function image(int $recordUid, string $fieldName, ?string $table = null): ?array
|
||||
public function image(int $recordUid, string $fieldName, ?string $table = null, bool $withCropVariants = false): ?array
|
||||
{
|
||||
try {
|
||||
$table = $table ?? self::TABLE;
|
||||
@@ -142,43 +143,92 @@ final class UsecaseSerializer
|
||||
];
|
||||
}
|
||||
|
||||
$cropString = (string)($ref['crop'] ?? '');
|
||||
$payload = $this->processImagePayload($imageService, $fileReference, $cropString !== '' ? $cropString : null);
|
||||
|
||||
$srcset = [];
|
||||
foreach (self::IMAGE_WIDTHS as $width) {
|
||||
$variant = $imageService->applyProcessingInstructions(
|
||||
$fileReference,
|
||||
['width' => $width, 'crop' => $ref['crop'] ?? null]
|
||||
);
|
||||
$srcset[] = [
|
||||
'url' => $imageService->getImageUri($variant),
|
||||
'width' => $width,
|
||||
'descriptor' => $width . 'w',
|
||||
];
|
||||
}
|
||||
|
||||
$default = $imageService->applyProcessingInstructions(
|
||||
$fileReference,
|
||||
['width' => 800, 'crop' => $ref['crop'] ?? null]
|
||||
);
|
||||
|
||||
return [
|
||||
$result = [
|
||||
'uid' => (int)$ref['uid'],
|
||||
'url' => $imageService->getImageUri($default),
|
||||
'url' => $payload['url'],
|
||||
'title' => (string)($ref['title'] ?? ''),
|
||||
'alternative' => (string)($ref['alternative'] ?? ''),
|
||||
'description' => (string)($ref['description'] ?? ''),
|
||||
'srcset' => $srcset,
|
||||
'srcset' => $payload['srcset'],
|
||||
'properties' => [
|
||||
'width' => $fileReference->getProperty('width'),
|
||||
'height' => $fileReference->getProperty('height'),
|
||||
'mimeType' => $fileReference->getProperty('mime_type'),
|
||||
],
|
||||
];
|
||||
|
||||
// Zusatz-Zuschnitte (Card 4:3 / Large Card 16:9) nur fuer das "erste Bild"
|
||||
// der karten-faehigen Modelle; faellt auf das Vollbild zurueck, wenn keine
|
||||
// Variante gesetzt ist.
|
||||
if ($withCropVariants) {
|
||||
$result['crops'] = $this->cropVariantPayloads($imageService, $fileReference, $cropString);
|
||||
}
|
||||
|
||||
return $result;
|
||||
} catch (\Throwable $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build {url, srcset} for one crop input (crop JSON string, absolute Area
|
||||
* or null = full image). srcset steps whose processing would fall back to
|
||||
* the original file are skipped (avoids raw-/403-leaks for sources that are
|
||||
* smaller than the requested width).
|
||||
*
|
||||
* @param string|\TYPO3\CMS\Core\Imaging\ImageManipulation\Area|null $crop
|
||||
* @return array{url:string,srcset:array<int,array<string,mixed>>}
|
||||
*/
|
||||
private function processImagePayload(ImageService $imageService, \TYPO3\CMS\Core\Resource\FileReference $fileReference, $crop): array
|
||||
{
|
||||
$srcset = [];
|
||||
foreach (self::IMAGE_WIDTHS as $width) {
|
||||
$variant = $imageService->applyProcessingInstructions(
|
||||
$fileReference,
|
||||
['width' => $width, 'crop' => $crop, 'fileExtension' => 'webp']
|
||||
);
|
||||
if ($variant->usesOriginalFile()) {
|
||||
continue;
|
||||
}
|
||||
$srcset[] = [
|
||||
'url' => $imageService->getImageUri($variant),
|
||||
'width' => $width,
|
||||
'descriptor' => $width . 'w',
|
||||
];
|
||||
}
|
||||
|
||||
$default = $imageService->applyProcessingInstructions(
|
||||
$fileReference,
|
||||
['width' => 800, 'crop' => $crop, 'fileExtension' => 'webp']
|
||||
);
|
||||
|
||||
return [
|
||||
'url' => $imageService->getImageUri($default),
|
||||
'srcset' => $srcset,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* card + largeCard crop-variant payloads for a model's first image.
|
||||
* Each variant falls back to the full image when no explicit crop is set.
|
||||
*
|
||||
* @return array<string,array{url:string,srcset:array<int,array<string,mixed>>}>
|
||||
*/
|
||||
private function cropVariantPayloads(ImageService $imageService, \TYPO3\CMS\Core\Resource\FileReference $fileReference, string $cropString): array
|
||||
{
|
||||
$collection = CropVariantCollection::create($cropString);
|
||||
$out = [];
|
||||
foreach (['card', 'largeCard'] as $variantKey) {
|
||||
$area = $collection->getCropArea($variantKey);
|
||||
$crop = $area->isEmpty() ? null : $area->makeAbsoluteBasedOnFile($fileReference);
|
||||
$out[$variantKey] = $this->processImagePayload($imageService, $fileReference, $crop);
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* All FAL images of one field (multi-reference), same shape as image().
|
||||
*
|
||||
@@ -260,13 +310,16 @@ final class UsecaseSerializer
|
||||
foreach (self::IMAGE_WIDTHS as $width) {
|
||||
$variant = $imageService->applyProcessingInstructions(
|
||||
$fileReference,
|
||||
['width' => $width, 'crop' => $ref['crop'] ?? null]
|
||||
['width' => $width, 'crop' => $ref['crop'] ?? null, 'fileExtension' => 'webp']
|
||||
);
|
||||
if ($variant->usesOriginalFile()) {
|
||||
continue; // Quelle zu klein fuer diese Breite: kein Raw-/403-Leak
|
||||
}
|
||||
$srcset[] = ['url' => $imageService->getImageUri($variant), 'width' => $width, 'descriptor' => $width . 'w'];
|
||||
}
|
||||
$default = $imageService->applyProcessingInstructions(
|
||||
$fileReference,
|
||||
['width' => 800, 'crop' => $ref['crop'] ?? null]
|
||||
['width' => 800, 'crop' => $ref['crop'] ?? null, 'fileExtension' => 'webp']
|
||||
);
|
||||
|
||||
return [
|
||||
|
||||
Reference in new issue
Block a user