Initial Commit

This commit is contained in:
khaccount committed 2026-05-18 14:46:25 +02:00
1 parent 4f495177e4
commit b6d2142214
166 files changed
+13952 -178

No files matched your search

@@ -0,0 +1,19 @@
<?php
namespace Evomedien\Vitec\Components;
namespace Evomedien\Vitec\Controller;
use TYPO3Fluid\Fluid\Core\Component\AbstractComponentCollection;
use TYPO3Fluid\Fluid\View\TemplatePaths;
final class ComponentCollection extends AbstractComponentCollection
{
public function getTemplatePaths(): TemplatePaths
{
$templatePaths = new TemplatePaths();
$templatePaths->setTemplateRootPaths([
'EXT:Vitec/Resources/Private/Components/',
]);
return $templatePaths;
}
}
@@ -0,0 +1,445 @@
<?php
declare(strict_types=1);
namespace Evomedien\Vitec\Controller;
use TYPO3\CMS\Core\Core\Environment;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Resource\FileRepository;
use TYPO3\CMS\Core\Mail\MailerInterface;
use TYPO3\CMS\Core\Mail\FluidEmail;
use TYPO3\CMS\Core\Http\ResponseFactory;
use TYPO3\CMS\Core\Http\Stream;
use TYPO3\CMS\Extbase\Http\ForwardResponse;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection;
use Evomedien\Vitec\Domain\Repository\DownloadRepository;
use Evomedien\Vitec\Domain\Repository\ProductRepository;
use Evomedien\Vitec\Domain\Model\Download;
/**
* This file is part of the "VITEC" Extension for TYPO3 CMS.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* (c) 2021
*/
/**
* DownloadController
*/
class DownloadController extends ActionController
{
protected DownloadRepository $downloadRepository;
protected ProductRepository $productRepository;
protected MailerInterface $mailer;
protected ResponseFactoryInterface $responseFactory;
public function __construct(
DownloadRepository $downloadRepository,
ProductRepository $productRepository,
MailerInterface $mailer,
ResponseFactoryInterface $responseFactory
) {
$this->downloadRepository = $downloadRepository;
$this->productRepository = $productRepository;
$this->mailer = $mailer;
$this->responseFactory = $responseFactory;
}
/**
* action list
*/
public function listAction(): ResponseInterface
{
$downloads = $this->downloadRepository->findAll();
$this->view->assign('downloads', $downloads);
return $this->htmlResponse();
}
/**
* action show
*/
public function showAction(): ResponseInterface
{
$products = $this->productRepository->findAlphabetically(false, false);
$ps = [];
$used = [];
foreach ($products as $p) {
if (!in_array($p->getUid(), $used)) {
$scat = $p->getProductsubcategory()->toArray();
$cat = $p->getProductcategory()->toArray();
if (!empty($scat)) {
$ps[$scat[0]->getTitle()][] = $p;
} elseif (!empty($cat)) {
$ps[$cat[0]->getTitle()][] = $p;
}
$used[] = $p->getUid();
}
}
ksort($ps);
$this->view->assign('settings', $this->settings);
$this->view->assign('products', $ps);
// $dcs = $this->dcRepository->fetchForWebsite();
// $this->view->assign('dcs', $dcs);
return $this->htmlResponse();
}
/**
* action directdownload
*/
public function directdownloadAction(Download $download): ResponseInterface
{
$json = $download->getForJSON();
$file = Environment::getProjectPath() . $json['file'];
if (!file_exists($file)) {
throw new \Exception('File not found', 404);
}
$response = $this->responseFactory->createResponse()
->withHeader('Content-Type', 'application/pdf')
->withHeader('Content-Disposition', 'inline; filename="' . basename($file) . '"')
->withHeader('Content-Transfer-Encoding', 'binary')
->withHeader('Accept-Ranges', 'bytes')
->withHeader('Content-Length', (string)filesize($file))
->withHeader('Pragma', 'public')
->withHeader('Expires', '0')
->withHeader('Cache-Control', 'must-revalidate');
$stream = new Stream(fopen($file, 'rb'));
return $response->withBody($stream);
}
/**
* action ac
*/
public function acAction(): ResponseInterface
{
$downloads = [];
$request = $this->request;
if (!empty($request->getQueryParams()['dc'])) {
$downloads = $this->downloadRepository->findByCategory($request->getQueryParams()['dc'], 1);
} elseif (!empty($request->getQueryParams()['k'])) {
$downloads = $this->downloadRepository->search($request->getQueryParams()['k'], 1);
} elseif (!empty($request->getQueryParams()['p'])) {
$downloads = $this->downloadRepository->findByProduct($request->getQueryParams()['p'], 1);
$product = $this->productRepository->findByUid($request->getQueryParams()['p']);
$this->view->assign('product', $product);
}
$this->downloadInfo($downloads);
return $this->htmlResponse();
}
private function downloadInfo($downloads): void
{
if (!empty($downloads)) {
$info = [];
foreach ($downloads as $d) {
$file = $d->getFile();
if (!empty($file)) {
$fileResourceReference = GeneralUtility::makeInstance(ResourceFactory::class)
->getFileReferenceObject($file->getUid());
$file = urldecode($fileResourceReference->getOriginalFile()->getPublicUrl());
$i = pathinfo($file);
$i['size'] = $this->human_filesize(filesize($file));
$info[$d->getUid()] = $i;
}
}
$this->view->assign('info', $info);
}
$this->view->assign('downloads', $downloads);
}
private function human_filesize($bytes, $decimals = 2): string
{
$sz = 'BKMGTP';
$factor = floor((strlen(strval($bytes)) - 1) / 3);
return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$sz[$factor];
}
/**
* action download
*/
public function downloadAction(Download $download): ResponseInterface
{
return $this->directdownloadAction($download);
}
public function combineddlAction(string $files): ResponseInterface
{
$ids = explode(',', $files);
$downloads = $this->downloadRepository->findByUids($ids);
$file = $this->createZip(md5($files), $downloads, null);
if ($file !== false) {
$response = $this->responseFactory->createResponse()
->withHeader('Content-disposition', 'attachment; filename=Vitec.zip')
->withHeader('Content-type', 'application/zip')
->withHeader('Content-Length', (string)filesize($file));
$stream = new Stream(fopen($file, 'rb'));
unlink($file);
return $response->withBody($stream);
}
return $this->htmlResponse();
}
/**
* action datasheets
*/
public function datasheetsAction(): ResponseInterface
{
$productso = $this->productRepository->fetchForDatasheets();
$sheets = [];
$faved = [];
$faves = [];
$request = $this->request;
if (!empty($_COOKIE['datasheet-faves'])) {
$faved = json_decode($_COOKIE['datasheet-faves']);
}
if (!empty($request->getParsedBody()['download'])) {
$downloads = $this->downloadRepository->findByUids($faved);
$file = $this->createZip($_COOKIE['datasheet-faves'], $downloads, null);
if ($file !== false) {
$response = $this->responseFactory->createResponse()
->withHeader('Content-disposition', 'attachment; filename=Vitec.zip')
->withHeader('Content-type', 'application/zip')
->withHeader('Content-Length', (string)filesize($file));
$stream = new Stream(fopen($file, 'rb'));
unlink($file);
return $response->withBody($stream);
}
}
if (!empty($productso)) {
foreach ($productso as $p) {
$downloads = $p->getDownload();
foreach ($downloads as $d) {
$isSheet = false;
foreach ($d->getType() as $t) {
// filter download type ids
if ($t->getUid() == 1 || $t->getUid() == 3) {
$isSheet = true;
break;
}
}
if ($isSheet) {
$cat = null;
$maincategorysort = 0;
foreach ($p->getProductcategory() as $c) {
$cat = $c->getTitle();
$maincategorysort = $c->getSort3();
break;
}
$subcat = null;
$subcatsort = 0;
foreach ($p->getProductsubcategory() as $s) {
$subcat = $s->getTitle();
$subcatsort = $s->getSort3();
break;
}
$isFaved = false;
if (in_array($d->getUid(), $faved)) {
$faves[] = [
'product' => $p,
'datasheet' => $d
];
$isFaved = true;
}
$sheets[] = [
'isfaved' => $isFaved,
'category' => $cat,
'sort' => $maincategorysort,
'subcategory' => $subcat,
'subcategorysort' => strval($subcatsort),
'product' => $p,
'datasheet' => $d
];
}
}
}
}
usort($sheets, function ($a, $b) {
if ($a["sort"] === $b["sort"]) {
if ($a["subcategorysort"] === $b["subcategorysort"]) {
return strcmp($a["product"]->getTitle(), $b["product"]->getTitle());
} else {
return strcmp($a["subcategorysort"], $b["subcategorysort"]);
}
}
return strcmp(strval($a["sort"]), strval($b["sort"]));
});
$this->view->assign('sheets', $sheets);
$this->view->assign('faves', $faves);
return $this->htmlResponse();
}
/**
* action index
*/
public function indexAction(): ResponseInterface
{
return $this->htmlResponse();
}
private function createZip($req, $downloads, $stories): string|false
{
$zip = new \ZipArchive();
$tmp_file = '/tmp/' . sha1($req) . '.zip';
if ($zip->open($tmp_file, \ZipArchive::CREATE)) {
if (!empty($downloads)) {
foreach ($downloads as $download) {
$f = $download->getFilepfad();
if ($f !== false) {
$zip->addFile($f, basename($f));
}
}
}
if (!empty($stories)) {
foreach ($stories as $story) {
$f = $story['pdf'];
if ($f !== false) {
$zip->addFile($f, basename($f));
}
}
}
$zip->close();
return $tmp_file;
}
return false;
}
/**
* action collection
*/
public function collectionAction(): ResponseInterface
{
$downloads = [];
$downloadids = [];
$stories = [];
$storyids = [];
$request = $this->request;
$parsedBody = $request->getParsedBody();
if (!empty($parsedBody['downloads'])) {
$ids = explode(',', $parsedBody['downloads']);
foreach ($ids as $id) {
$downloadids[] = intval($id);
}
$downloadids = implode(',', $downloadids);
$downloads = $this->downloadRepository->findByUids($ids);
}
if (!empty($parsedBody['stories'])) {
$ids = explode(',', $parsedBody['stories']);
foreach ($ids as $id) {
$storyids[] = intval($id);
}
$storyids = implode(',', $storyids);
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable('tt_content');
$whereExpressions = [
$queryBuilder->expr()->eq('colPos', $queryBuilder->createNamedParameter(0)),
$queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter(18)),
$queryBuilder->expr()->in(
'uid',
$queryBuilder->createNamedParameter(
explode(',', $storyids),
Connection::PARAM_INT_ARRAY
)
),
$queryBuilder->expr()->eq('CType', $queryBuilder->createNamedParameter('mask_use_case')),
$queryBuilder->expr()->eq('tx_mask_app_visible', $queryBuilder->createNamedParameter(1))
];
$result = $queryBuilder->select('tt_content.*')
->from('tt_content')
->where(...$whereExpressions)
->orderBy('tt_content.sorting')
->executeQuery();
$rows = $result->fetchAllAssociative();
$fileRepository = GeneralUtility::makeInstance(FileRepository::class);
foreach ($rows as $content) {
$pdf_url = '';
$filename = '';
if (!empty($content['tx_mask_detail_pdf'])) {
try {
$filename = Environment::getProjectPath() . '/' . $content['tx_mask_detail_pdf'];
$pdf_url = $this->uriBuilder->setTargetPageUid(1)->buildFrontendUri() .
substr(str_replace(Environment::getProjectPath(), '', $filename), 1);
} catch (\Exception $e) {
// Handle exception
}
}
$stories[$content['uid']] = [
'uid' => $content['uid'],
'header' => $content['header'],
'pdf' => $filename,
'detail_pdf' => $pdf_url
];
}
}
if (!empty($parsedBody['email']) &&
filter_var($parsedBody['email'], FILTER_VALIDATE_EMAIL) &&
(!empty($parsedBody['downloads']) || !empty($parsedBody['stories']))) {
$file = $this->createZip($parsedBody['downloads'] . $parsedBody['stories'], $downloads, $stories);
if ($file !== false) {
$email = GeneralUtility::makeInstance(FluidEmail::class);
$email->from('downloads@vitec.com', 'VITEC')
->to($parsedBody['email'])
->subject('VITEC Datasheets download')
->text('Thank you for your interest in VITEC products. Attached, please find your Datasheets ready for download.')
->attachFromPath($file, 'Vitec.zip');
$this->mailer->send($email);
$redirect = $this->uriBuilder->setTargetPageUid(186)->setCreateAbsoluteUri(true)->buildFrontendUri();
return $this->redirectToUri($redirect);
}
} elseif (!empty($parsedBody['downloads']) || !empty($parsedBody['stories'])) {
$file = $this->createZip($parsedBody['downloads'] . $parsedBody['stories'], $downloads, $stories);
if ($file !== false) {
$response = $this->responseFactory->createResponse()
->withHeader('Content-disposition', 'attachment; filename=Vitec.zip')
->withHeader('Content-type', 'application/zip')
->withHeader('Content-Length', (string)filesize($file));
$stream = new Stream(fopen($file, 'rb'));
unlink($file);
return $response->withBody($stream);
}
}
$this->view->assign('downloads', $downloads);
$this->view->assign('downloadids', $downloadids);
$this->view->assign('stories', $stories);
$this->view->assign('storyids', $storyids);
return $this->htmlResponse();
}
}
@@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace Evomedien\Vitec\Controller;
use Evomedien\Vitec\Domain\Repository\MarketRepository;
use Evomedien\Vitec\Domain\Model\Market;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use Psr\Http\Message\ResponseInterface;
/**
* This file is part of the "VITEC" Extension for TYPO3 CMS.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* (c) 2025
*/
/**
* MarketController
*/
class MarketController extends ActionController
{
/**
* marketRepository
*
* @var MarketRepository
*/
protected $marketRepository;
/**
* Constructor
*
* @param MarketRepository $marketRepository
*/
public function __construct(MarketRepository $marketRepository)
{
$this->marketRepository = $marketRepository;
}
/**
* action show
*
* @return ResponseInterface
*/
public function showAction(): ResponseInterface
{
$selectedMarketId = (int)$this->settings['market'];
$market = null;
if ($selectedMarketId) {
$market = $this->marketRepository->findByUid($selectedMarketId);
}
$this->view->assign('market', $market);
return $this->htmlResponse();
}
}
@@ -0,0 +1,199 @@
<?php
declare(strict_types=1);
namespace Evomedien\Vitec\Controller;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use Evomedien\Vitec\Domain\Repository\ProductRepository;
use Evomedien\Vitec\PageTitle\ProductPageTitleProvider;
use TYPO3\CMS\Core\Routing\PageLinkBuilder;
use TYPO3\CMS\Core\LinkHandling\LinkService;
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Core\MetaTag\MetaTagManagerRegistry;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* This file is part of the "VITEC" Extension for TYPO3 CMS.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* (c) 2025
*/
/**
* ProductController
*/
class ProductController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
{
/**
* productRepository
*
* @var \Evomedien\Vitec\Domain\Repository\ProductRepository
*/
protected $productRepository;
/**
* @var \Evomedien\Vitec\PageTitle\ProductPageTitleProvider
*/
protected $titleProvider;
/**
* @param \Evomedien\Vitec\Domain\Repository\ProductRepository $productRepository
*/
public function injectProductRepository(\Evomedien\Vitec\Domain\Repository\ProductRepository $productRepository)
{
$this->productRepository = $productRepository;
}
/**
* Inject the TitleProvider
*
* @param \Evomedien\Vitec\PageTitle\ProductPageTitleProvider $titleProvider
*/
public function injectTitleProvider(ProductPageTitleProvider $titleProvider): void
{
$this->titleProvider = $titleProvider;
}
/**
* @var LinkService
*/
protected $linkService;
/**
* Constructor
*
* @param ProductRepository $productRepository
* @param ProductPageTitleProvider $titleProvider
* @param LinkService $linkService
*/
public function __construct(
ProductRepository $productRepository,
ProductPageTitleProvider $titleProvider,
) {
$this->productRepository = $productRepository;
$this->titleProvider = $titleProvider;
}
/**
* action index
*
* @return \Psr\Http\Message\ResponseInterface
*/
public function indexAction(): \Psr\Http\Message\ResponseInterface
{
return $this->htmlResponse();
}
/**
* action list
*
* @return \Psr\Http\Message\ResponseInterface
*/
public function listAction(): \Psr\Http\Message\ResponseInterface
{
// Extract and sanitize category UIDs from FlexForm
$categoryUids = array_filter(
array_map('intval', explode(',', (string)($this->settings['categories'] ?? '')))
);
// Get filtered products based on categories and visibility flags
$products = $this->productRepository->findFilteredProducts($categoryUids);
$this->view->assign('products', $products);
// Check if we're in headless mode (JSON request)
$request = $this->request;
$pageType = $request->getAttribute('routing')?->getPageType() ?? 0;
if ($pageType === 834) { // Headless JSON page type
return $this->jsonResponse(json_encode([
'products' => $this->serializeProducts($products)
]));
}
return $this->htmlResponse();
}
/**
* Serialize products to array for JSON output
*/
protected function serializeProducts($products): array
{
$productsData = [];
foreach ($products as $product) {
$categories = [];
if ($product->getCategories()) {
foreach ($product->getCategories() as $category) {
$categories[] = [
'uid' => $category->getUid(),
'title' => $category->getTitle(),
];
}
}
$image = null;
if ($product->getProductimage() && $product->getProductimage()->count() > 0) {
$imageObject = $product->getProductimage()->current();
$image = [
'uid' => $imageObject->getUid(),
'url' => $imageObject->getOriginalResource()->getPublicUrl(),
'title' => $imageObject->getTitle(),
'alternative' => $imageObject->getAlternative(),
'description' => $imageObject->getDescription(),
];
}
$productsData[] = [
'uid' => $product->getUid(),
'title' => $product->getTitle(),
'subtitle' => $product->getSubtitle(),
'teaser' => $product->getTeaser(),
'description' => $product->getDescription(),
'slug' => $product->getSlug(),
'categories' => $categories,
'image' => $image,
];
}
return $productsData;
}
/**
* action show
*
* @param \Evomedien\Vitec\Domain\Model\Product $product
* @return \Psr\Http\Message\ResponseInterface
*/
public function showAction(\Evomedien\Vitec\Domain\Model\Product $product): \Psr\Http\Message\ResponseInterface
{
$metaTagManager = GeneralUtility::makeInstance(MetaTagManagerRegistry::class)->getManagerForProperty('og:title');
$metaTagManager->addProperty('og:title', ($product->getSeotitle()));
$metaTagManager->addProperty('og:description', ($product->getDescription()));
//$metaTagManager->addProperty('og:url', $this->request->getRequestUri());
$metaTagManager->addProperty('og:type', 'product');
if ($product->getOgimage()) {
$ogImageUrl = $product->getOgimage()->getOriginalResource()->getPublicUrl();
$metaTagManager->addProperty('og:image', $ogImageUrl);
}
// Access the layout setting from FlexForm
$layout = $this->settings['layout'] ?? 0;
// Pass the layout to the view
$this->view->assign('layout', $layout);
$this->view->assign('product', $product);
$this->titleProvider->setSeoTitle($product->getSeotitle());
return $this->htmlResponse();
}
}
@@ -0,0 +1,12 @@
<?php
namespace Evomedien\Vitec\Controller;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
class SimplecardController extends ActionController
{
public function listAction(): \Psr\Http\Message\ResponseInterface
{
return $this->htmlResponse();
}
}
@@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace Evomedien\Vitec\Controller;
use Evomedien\Vitec\Domain\Repository\SolutionRepository;
use Evomedien\Vitec\Domain\Model\Solution;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use Psr\Http\Message\ResponseInterface;
/**
* This file is part of the "VITEC" Extension for TYPO3 CMS.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* (c) 2025
*/
/**
* SolutionController
*/
class SolutionController extends ActionController
{
/**
* solutionRepository
*
* @var SolutionRepository
*/
protected $solutionRepository;
/**
* Constructor
*
* @param SolutionRepository $solutionRepository
*/
public function __construct(SolutionRepository $solutionRepository)
{
$this->solutionRepository = $solutionRepository;
}
/**
* action show
*
* @return ResponseInterface
*/
public function showAction(): ResponseInterface
{
$selectedSolutionId = (int)$this->settings['solution'];
$solution = null;
if ($selectedSolutionId) {
$solution = $this->solutionRepository->findByUid($selectedSolutionId);
}
$this->view->assign('solution', $solution);
return $this->htmlResponse();
}
}
@@ -0,0 +1,75 @@
<?php
declare(strict_types=1);
namespace Evomedien\Vitec\Controller;
use Evomedien\Vitec\Domain\Repository\UsecaseRepository;
use Evomedien\Vitec\Domain\Model\Usecase;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use Psr\Http\Message\ResponseInterface;
/**
* This file is part of the "VITEC" Extension for TYPO3 CMS.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* (c) 2025
*/
/**
* UsecaseController
*/
class UsecaseController extends ActionController
{
/**
* usecaseRepository
*
* @var UsecaseRepository
*/
protected $usecaseRepository;
/**
* Constructor
*
* @param UsecaseRepository $usecaseRepository
*/
public function __construct(UsecaseRepository $usecaseRepository)
{
$this->usecaseRepository = $usecaseRepository;
}
/**
* action show
*
* @param Usecase $usecase
* @return ResponseInterface
*/
public function showAction(): ResponseInterface
{
$selectedUsecaseId = (int)$this->settings['usecase']; // Die ID aus dem Flexform
$usecase = null;
if ($selectedUsecaseId) {
$usecase = $this->usecaseRepository->findByUid($selectedUsecaseId);
}
$this->view->assign('usecase', $usecase);
return $this->htmlResponse();
}
/**
* action list
*
* @param Usecase $usecase
* @return ResponseInterface
*/
public function listAction(): ResponseInterface
{
$usecases = $this->usecaseRepository->findAllWithCategories();
$this->view->assign('usecases', $usecases);
return $this->htmlResponse();
}
}