VITEC headless: ContentElementResolver, Product fields (videofile, showdatapath)

- New Classes/Service/ContentElementResolver.php: parses TYPO3 typolink
  (t3://record?identifier=tt_content&uid=N, t3://page?uid=P#N, plain numeric)
  to a normalised tt_content envelope ({id,type,colPos,sorting,appearance,
  data}), recursively resolving any nested VITEC list-plugin children.
- ProductListJsonRenderer / ProductShowJsonRenderer: contentelement and
  contentelementcta now emit the resolved object instead of the raw
  typolink string (breaking change at those two keys).
- Product model: new field videofile (FAL, single video upload in tab
  Images and Videos, mp4/webm/ogv/mov/m4v); new bool field showdatapath
  (toggle at end of General tab, controls the "Datapath is now Vitec"
  graphic in the frontend). ext_tables.sql, TCA, model property +
  getter/setter, and both renderers updated accordingly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
o-rascheandClaude Opus 4.7 committed 2026-06-05 10:34:49 +02:00
1 parent dba154e572
commit 409afc2433
34 files changed
+461 -9

No files matched your search

@@ -155,8 +155,8 @@ class ProductListJsonRenderer
'description' => (string)($product['description'] ?? ''),
'highlights' => (string)($product['highlights'] ?? ''),
'shortcutpid' => (string)($product['shortcutpid'] ?? ''),
'contentelement' => (string)($product['contentelement'] ?? ''),
'contentelementcta' => (string)($product['contentelementcta'] ?? ''),
'contentelement' => \Evomedien\Vitec\Service\ContentElementResolver::resolveLink((string)($product['contentelement'] ?? '')),
'contentelementcta' => \Evomedien\Vitec\Service\ContentElementResolver::resolveLink((string)($product['contentelementcta'] ?? '')),
'hideonapp' => (bool)($product['hideonapp'] ?? false),
'hideonwebsite' => (bool)($product['hideonwebsite'] ?? false),
@@ -166,6 +166,7 @@ class ProductListJsonRenderer
'legacy' => (bool)($product['legacy'] ?? false),
'supportproduct' => (bool)($product['supportproduct'] ?? false),
'subproduct' => (bool)($product['subproduct'] ?? false),
'showdatapath' => (bool)($product['showdatapath'] ?? false),
'link' => '/product/' . (string)($product['slug'] ?? ''),
@@ -173,6 +174,7 @@ class ProductListJsonRenderer
'images' => $this->getProductImages($uid),
'downloads' => $this->getProductDownloads($uid),
'ogimage' => $this->getProductOgImage($uid),
'videofile' => $this->getProductVideoFile($uid),
'relatedprodukt' => $this->getRelatedProducts($uid),
];
}
@@ -310,6 +312,49 @@ class ProductListJsonRenderer
}
}
/**
* Resolve the uploaded video file (single FAL reference, fieldname=videofile).
*
* @return array<string,mixed>|null
*/
protected function getProductVideoFile(int $productUid): ?array
{
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
->getQueryBuilderForTable('sys_file_reference');
$row = $queryBuilder
->select('fr.uid', 'fr.title', 'fr.description', 'f.uid as file_uid', 'f.identifier', 'f.name', 'f.size', 'f.extension', 'f.mime_type')
->from('sys_file_reference', 'fr')
->join('fr', 'sys_file', 'f', 'fr.uid_local = f.uid')
->where(
$queryBuilder->expr()->eq('fr.tablenames', $queryBuilder->createNamedParameter('tx_vitec_domain_model_product', \Doctrine\DBAL\ParameterType::STRING)),
$queryBuilder->expr()->eq('fr.fieldname', $queryBuilder->createNamedParameter('videofile', \Doctrine\DBAL\ParameterType::STRING)),
$queryBuilder->expr()->eq('fr.uid_foreign', $queryBuilder->createNamedParameter($productUid, \Doctrine\DBAL\ParameterType::INTEGER)),
$queryBuilder->expr()->eq('fr.deleted', 0),
$queryBuilder->expr()->eq('fr.hidden', 0),
$queryBuilder->expr()->eq('f.missing', 0)
)
->orderBy('fr.sorting_foreign', 'ASC')
->setMaxResults(1)
->executeQuery()
->fetchAssociative();
if (!$row) {
return null;
}
return [
'uid' => (int)$row['file_uid'],
'name' => (string)($row['name'] ?? ''),
'url' => '/fileadmin' . ($row['identifier'] ?? ''),
'size' => (int)($row['size'] ?? 0),
'extension' => (string)($row['extension'] ?? ''),
'mimeType' => (string)($row['mime_type'] ?? ''),
'title' => (string)($row['title'] ?? ''),
'description' => (string)($row['description'] ?? ''),
];
}
protected function getProductCategories(int $productUid): array
{
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)